Skip to content

Discover hooks via inspect.getattr_static#701

Open
RonnyPfannschmidt wants to merge 13 commits into
pytest-dev:mainfrom
RonnyPfannschmidt:getattr-static-hook-discovery
Open

Discover hooks via inspect.getattr_static#701
RonnyPfannschmidt wants to merge 13 commits into
pytest-dev:mainfrom
RonnyPfannschmidt:getattr-static-hook-discovery

Conversation

@RonnyPfannschmidt

Copy link
Copy Markdown
Member

Summary

  • Follow-up to Avoid triggering @property methods on plugins when looking for hookimpls during registration #536: replace property/AttributeError special-casing with narrow inspect.getattr_static discovery.
  • Only functions, classmethod, staticmethod, and bound methods are treated as hookable; properties/cached_property/other descriptors are skipped without executing them.
  • Bind callables via __get__ instead of discovery getattr.
  • Also discovers @hookimpl applied above @classmethod/@staticmethod (previously missed when registering instances).

Depends on #536 — this branch is stacked on that PR. Merge #536 first, then rebase this onto main (or merge as-is after #536 lands).

Test plan

  • uv run pytest (149 passed)
  • uv run pre-commit run -a
  • property / cached_property / raising-descriptor registration tests
  • @hookimpl above classmethod/staticmethod tests

Made with Cursor

pirate and others added 12 commits September 26, 2024 20:39
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.6.7 → v0.6.8](astral-sh/ruff-pre-commit@v0.6.7...v0.6.8)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
Co-authored-by: Ran Benita <ran@unusedvar.com>
Document the generic descriptor/proxy AttributeError skip and cover it
with a minimal raising-descriptor plugin so the path is tested without
pydantic.

Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Cursor Grok 4.5 <grok@x.ai>
Only treat functions, classmethods, staticmethods, and bound methods as
hookable, so properties and other descriptors are never executed during
registration. Also discovers @hookimpl applied above classmethod/staticmethod.

Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Cursor Grok 4.5 <grok@x.ai>
Copilot AI review requested due to automatic review settings July 21, 2026 08:27
Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Cursor Grok 4.5 <grok@x.ai>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR refines Pluggy’s plugin hook discovery during PluginManager.register() and hookspec parsing by switching to inspect.getattr_static-based lookup to avoid triggering descriptors (e.g., @property, cached_property) while discovering @hookimpl/@hookspec markers. It also improves support for marker placement with @hookimpl stacked above @classmethod/@staticmethod, and binds callables via __get__ instead of using getattr() during discovery.

Changes:

  • Add static (descriptor-safe) hook discovery helpers in PluginManager to skip properties/other descriptors without executing them.
  • Discover @hookimpl markers when applied above @classmethod/@staticmethod wrappers.
  • Add targeted regression tests ensuring registration does not evaluate properties/cached properties/raising descriptors and supports the new decorator ordering cases.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/pluggy/_manager.py Implements inspect.getattr_static-based marker discovery and callable binding to avoid executing descriptors during registration/spec parsing.
testing/test_pluginmanager.py Adds tests covering descriptor-safety during registration and hookimpl discovery for @hookimpl above @classmethod/@staticmethod.

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

Comment thread src/pluggy/_manager.py
Comment on lines +68 to +71
if inspect.isfunction(static):
if inspect.isclass(obj) or inspect.ismodule(obj):
return static
return static.__get__(obj, type(obj))
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.

3 participants