Skip to content

Fix @inject on classmethod returning wrong cls in subclass hierarchy - #978

Merged
ZipFile merged 5 commits into
ets-labs:developfrom
deepakganesh78:fix/issue947-classmethod-inject-cls
Aug 4, 2026
Merged

Fix @inject on classmethod returning wrong cls in subclass hierarchy#978
ZipFile merged 5 commits into
ets-labs:developfrom
deepakganesh78:fix/issue947-classmethod-inject-cls

Conversation

@deepakganesh78

Copy link
Copy Markdown

Fixes #947

Problem

When a @classmethod decorated with @Inject is inherited through multiple levels (Base -> Sub1 -> Sub2), calling Sub2.injected_factory() incorrectly returns an instance of Sub1 instead of Sub2.

Root Cause

In _patch_method, when processing inherited classmethods on subclasses, the method is not in the subclass's dict, so the code gets a bound method from getmembers. This bound method has cls already baked in. Since the bound method itself isn't registered as patched, the code wraps it again and sets the result as a plain function on the subclass via setattr. This breaks the classmethod descriptor protocol — deeper subclasses inherit the patched plain function (with the wrong cls) instead of going through the classmethod descriptor.

Fix

In the else branch of _patch_method (inherited methods), check if the underlying func is already patched. If so, skip — the parent class's classmethod descriptor will correctly provide cls to all subclasses through normal Python inheritance.

Validation

  • Regression test added: ests/unit/wiring/test_classmethod_inject_inheritance_py36.py
  • All 76 existing wiring tests pass (3 async tests skipped due to missing pytest-asyncio)
  • Tested with Python 3.13

ZipFile and others added 3 commits March 22, 2026 21:07
When _patch_method processed inherited classmethods on subclasses, it would
wrap the already-bound method (which has cls baked in) and set it as a plain
function on the subclass. This broke the classmethod descriptor protocol,
causing deeper subclasses to receive the wrong cls.

The fix skips re-patching inherited methods whose underlying __func__ is
already patched by the parent class, preserving correct cls binding through
normal Python inheritance.

Fixes ets-labs#947

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ZipFile
ZipFile force-pushed the fix/issue947-classmethod-inject-cls branch from 57aa252 to 3d143f8 Compare August 4, 2026 18:33
@coveralls

coveralls commented Aug 4, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 92.402% (+0.03%) from 92.377% — deepakganesh78:fix/issue947-classmethod-inject-cls into ets-labs:master

@ZipFile
ZipFile force-pushed the fix/issue947-classmethod-inject-cls branch from 3d143f8 to 186d71a Compare August 4, 2026 18:35

@ZipFile ZipFile 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.

Thanks!

@ZipFile
ZipFile changed the base branch from master to develop August 4, 2026 18:40
@ZipFile
ZipFile merged commit 634ccec into ets-labs:develop Aug 4, 2026
14 checks passed
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.

Bug: Wrong cls type in combination of @classmethod and @inject

3 participants