Skip to content

fix(stdlib): resolve postponed annotations in generative stub signature - #1504

Merged
planetf1 merged 3 commits into
generative-computing:mainfrom
planetf1:issue-1476
Aug 6, 2026
Merged

fix(stdlib): resolve postponed annotations in generative stub signature#1504
planetf1 merged 3 commits into
generative-computing:mainfrom
planetf1:issue-1476

Conversation

@planetf1

@planetf1 planetf1 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Pull Request

Issue

Fixes #1503

Description

Under from __future__ import annotations (PEP 563 postponed annotations), @generative stub signatures were corrupted before being sent to the model.

  • describe_function() used inspect.signature(func), which renders postponed annotations as literal strings — (product_description: str) -> list[Requirement] became (product_description: 'str') -> 'list[Requirement]' in the prompt.
  • get_argument() had the same issue at the parameter level: param.annotation was the string "str" rather than the type str, so the param_type is str check failed and string arguments were rendered unquoted (value: Alice instead of value: "Alice").

Both are fixed by passing eval_str=True to inspect.signature(), which resolves the annotation strings back to real types — the same resolution create_response_format() already gets for free via typing.get_type_hints().

Why eval_str=True is safe here: any annotation that would raise under eval_str=True (e.g. TYPE_CHECKING-only imports, forward references to not-yet-defined classes) already raises the identical NameError from the pre-existing get_type_hints(func) call in create_response_format(), which every @generative-decorated function goes through at decoration time. So this cannot break any function that could previously be decorated with @generative — it only changes which of two co-located calls raises first.

The two other inspect.signature(func) call sites in this file (bind_function_arguments() and GenerativeStub.__init__'s disallowed-param-name check) are deliberately left unchanged — neither inspects .annotation, so PEP 563 doesn't affect them, and adding eval_str there would only add a failure mode for no benefit.

Follow-ups (out of scope here):

Testing

  • Tests added to the respective file if code was changed
  • New code has 100% coverage if code was added
  • Ensure existing tests and github automation passes (a maintainer will kick off the github automation when the rest of the PR is populated)

Added test/stdlib/components/_pep563_fixtures.py, a fixture module with from __future__ import annotations (isolated in its own file since the import is a module-level directive), and two regression tests in test/stdlib/components/test_genstub_unit.py — each with a precondition guard on __annotations__ so they can't pass vacuously if PEP 563 is later dropped from the fixture module.

uv run python -m pytest test/stdlib/components/test_genstub_unit.py -v — 33 passed. uv run ruff format --check, uv run ruff check, uv run mypy — all clean on the three changed files.

Attribution

  • AI coding assistants used

Adding a new component, requirement, sampling strategy, or tool?

If your PR adds or modifies one of the types below, check the matching box. A checklist of type-specific review items will be posted as a comment.

  • Component
  • Requirement
  • Sampling Strategy
  • Tool

NOTE: Please ensure you have an issue that has been acknowledged by a core contributor and routed you to open a pull request against this repository. Otherwise, please open an issue before continuing with this pull request.

inspect.signature(func) returns literal annotation strings when the
caller's module has `from __future__ import annotations` (PEP 563),
corrupting both the rendered function signature and the argument
value-quoting check in describe_function()/get_argument(). Pass
eval_str=True so annotations resolve the same way
typing.get_type_hints() already resolves them elsewhere in the
codebase.

Fixes generative-computing#1503

Assisted-by: Claude Code
Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
Regression test comments cited generative-computing#1476 (the original, unrelated report)
instead of generative-computing#1503 (this fix); per project convention, drop the numeric
ref rather than just correct it. Also pin each test's precondition via
__annotations__ so it can't pass vacuously if the fixture module ever
drops `from __future__ import annotations`.

Assisted-by: Claude Code
Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
@github-actions github-actions Bot added the bug Something isn't working label Aug 6, 2026
@planetf1
planetf1 marked this pull request as ready for review August 6, 2026 00:36
@planetf1
planetf1 requested a review from a team as a code owner August 6, 2026 00:36
Match the module-top-level import style used in PR generative-computing#1509's
test/backends/test_tools_pep563.py for the same fixture pattern.

Assisted-by: Claude Code
Signed-off-by: Nigel Jones <jonesn@uk.ibm.com>
@planetf1
planetf1 added this pull request to the merge queue Aug 6, 2026
Merged via the queue into generative-computing:main with commit c472907 Aug 6, 2026
10 checks passed
@planetf1
planetf1 deleted the issue-1476 branch August 6, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(stdlib): @generative stub signature corrupted under from __future__ import annotations

2 participants