Skip to content

fix(tests): fix Python 3.10-only mock.patch AttributeError in fknm fallback tests - #539

Merged
petercorke merged 2 commits into
mainfrom
fix/py310-mock-patch-shadowing
Jul 5, 2026
Merged

fix(tests): fix Python 3.10-only mock.patch AttributeError in fknm fallback tests#539
petercorke merged 2 commits into
mainfrom
fix/py310-mock-patch-shadowing

Conversation

@petercorke

Copy link
Copy Markdown
Owner

Summary

Root-caused the Python-3.10-only AttributeError: <class 'roboticstoolbox.robot.ETS.ETS'> does not have the attribute 'ETS_jacob0' (and jacobe/hessian0/hessiane/fkine) seen on main's CI. Not a real code bug — the actual fknm C-extension/pure-Python fallback machinery was fine the whole time.

The actual cause: roboticstoolbox/robot/ETS.py defines a class also called ETS, and robot/__init__.py's from ...ETS import ETS rebinds the "ETS" attribute on the roboticstoolbox.robot package to the class, shadowing the submodule of the same name. Python 3.10's unittest.mock resolves dotted-string patch() targets via plain getattr (falling back to import only on AttributeError), so patch("...ETS.ETS_fkine", ...) resolved "ETS" to the shadowing class and failed. Python 3.11+ rewrote this to use pkgutil.resolve_name, which isn't fooled by the same shadowing — hence it only ever showed up on 3.10.

Fix: look up the real module via sys.modules["roboticstoolbox.robot.ETS"] (a plain dict keyed by the literal string, no getattr involved — even import ... as x doesn't avoid the shadowing, since that's defined as import ...; x = ..., still attribute access) and use patch.object() against that instead of a dotted string.

Test plan

  • All 41 tests in test_fknm_fallback.py pass under Python 3.10
  • All 41 tests pass under Python 3.13 (no regression)

🤖 Generated with Claude Code

petercorke and others added 2 commits July 5, 2026 10:44
…llback tests

roboticstoolbox/robot/ETS.py defines a class also called ETS, and
robot/__init__.py's `from ...ETS import ETS` rebinds the "ETS"
attribute on the roboticstoolbox.robot package to the class, shadowing
the submodule of the same name. Python 3.10's unittest.mock resolves
dotted-string patch targets via plain getattr (falling back to import
only on AttributeError), so patch("...ETS.ETS_fkine", ...) resolved
"ETS" to the shadowing class and failed with AttributeError; 3.11+
uses pkgutil.resolve_name and isn't fooled by the same shadowing. This
is why it only ever showed up on Python 3.10 in CI.

Not a real code bug - the actual fknm/facade fallback machinery was
always fine, only the test's patch target resolution was broken on
3.10. Fixed by looking up the real module via sys.modules directly
(the only lookup with no getattr involved) and patching against that
with patch.object() instead of a dotted string.

Rehearsed: all 41 tests in test_fknm_fallback.py pass under both
Python 3.10 and 3.13.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cross-references the fknm fallback test fix in this same branch.
Python 3.10 reaches EOL October 2026 — flag this specific workaround
for removal (and a general 3.10-specific-code sweep) at that point.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@petercorke
petercorke merged commit 38be2c4 into main Jul 5, 2026
10 of 16 checks passed
@github-actions github-actions Bot mentioned this pull request Jul 4, 2026
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.

1 participant