Skip to content

[NO-SQUASH-MERGE] fix varnames on py3.14 deferred annotations#632

Open
RonnyPfannschmidt wants to merge 9 commits intopytest-dev:mainfrom
RonnyPfannschmidt:varnames-no-resolve-types
Open

[NO-SQUASH-MERGE] fix varnames on py3.14 deferred annotations#632
RonnyPfannschmidt wants to merge 9 commits intopytest-dev:mainfrom
RonnyPfannschmidt:varnames-no-resolve-types

Conversation

@RonnyPfannschmidt
Copy link
Copy Markdown
Member

closes #629

using direct attributes instead of signature to avoid the extra objects

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes pluggy._hooks.varnames() to avoid inspect.signature() on Python 3.14+ (where deferred/string annotations may be resolved and can fail), and adds coverage + benchmarks around the new behavior.

Changes:

  • Reimplements varnames() using __code__, __defaults__, and __qualname__ instead of inspect.signature().
  • Adds a regression test for annotations that cannot be resolved at runtime.
  • Extends benchmark suite to compare the new implementation against a legacy inspect.signature() version.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/pluggy/_hooks.py Updates varnames() implementation to avoid annotation resolution and reduce overhead.
testing/test_helpers.py Adds a regression test ensuring varnames() works with unresolvable string annotations.
testing/benchmark.py Adds microbenchmarks comparing new vs legacy varnames() approaches.
Comments suppressed due to low confidence (1)

src/pluggy/_hooks.py:298

  • Typo in the varnames docstring: "keywrord" should be "keyword".
def varnames(func: object) -> tuple[tuple[str, ...], tuple[str, ...]]:
    """Return tuple of positional and keywrord argument names for a function,
    method, class or callable.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/pluggy/_hooks.py Outdated
Comment thread testing/test_helpers.py Outdated
@RonnyPfannschmidt RonnyPfannschmidt force-pushed the varnames-no-resolve-types branch from b93eafb to 9d852b3 Compare April 29, 2026 18:21
RonnyPfannschmidt and others added 3 commits April 29, 2026 20:31
In Python 3.14+, annotations are evaluated lazily per PEP 649/749.
When inspect.signature() is called, it tries to resolve annotations
by default, which fails if the annotation references an undefined type.

Add a version-gated _signature helper that uses
annotation_format=annotationlib.Format.STRING on Python 3.14+ to
prevent annotation resolution errors.

Fixes pytest-dev#629

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Use code object attributes (co_varnames, co_argcount) and __defaults__
directly instead of inspect.signature(). This avoids annotation
resolution entirely, which is simpler and more efficient.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Include both the current implementation and the legacy inspect.signature-based
version to clearly demonstrate the ~7-66x speedup from using code objects directly.

Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Anthropic Claude Opus 4 <claude@anthropic.com>
@RonnyPfannschmidt RonnyPfannschmidt force-pushed the varnames-no-resolve-types branch from 9d852b3 to d2775b4 Compare April 29, 2026 18:33
RonnyPfannschmidt and others added 3 commits April 29, 2026 21:27
Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Anthropic Claude Opus 4 <claude@anthropic.com>
A module-level function assigned to a class attribute becomes a bound
method on instances, but its __qualname__ has no dot. Track whether
the original callable was a bound method before unwrapping to __func__,
so self is always stripped for bound methods.

Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Anthropic Claude Opus 4 <claude@anthropic.com>
Replace exec()-based test with a direct function definition. The string
annotation "NonExistentType" triggers the same behavior without the
indirection.

Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Anthropic Claude Opus 4 <claude@anthropic.com>
@RonnyPfannschmidt RonnyPfannschmidt changed the title fix varnames on py3.14 deferred annotations [NO-SQUAHS-MERGE] fix varnames on py3.14 deferred annotations Apr 29, 2026
@RonnyPfannschmidt RonnyPfannschmidt changed the title [NO-SQUAHS-MERGE] fix varnames on py3.14 deferred annotations [NO-SQUASH-MERGE] fix varnames on py3.14 deferred annotations Apr 29, 2026
Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Anthropic Claude Opus 4 <claude@anthropic.com>
Copy link
Copy Markdown
Member

@bluetech bluetech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit wary of stopping to use inspect.signature. It means we drop support for stuff like __signature__ and __text_signature__ and whatever weird stuff inspect.signature supports.

The performance is definitely nice but if I'm not mistaken varnames is only used #hookspecs + #hookimpls times so not very performance critical.

Nonetheless, if you think it should be fine, I would at least suggest running some downstream tests (see downstream/ directory) to make sure there are no regressions (I usually run it before release).

Comment thread src/pluggy/_hooks.py Outdated
Comment thread testing/benchmark.py
Comment thread changelog/629.bugfix.rst Outdated
RonnyPfannschmidt and others added 2 commits May 1, 2026 08:42
…lusion

Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Anthropic Claude Opus 4 <claude@anthropic.com>
Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Anthropic Claude Opus 4 <claude@anthropic.com>
Made-with: Cursor
@RonnyPfannschmidt
Copy link
Copy Markdown
Member Author

RonnyPfannschmidt commented May 1, 2026

fixing the downstream tests now (scripts are bitrot affected)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pluggy requires from __future__ import annotations although it shouldn't in Python 3.14

3 participants