Skip to content

fix(linalg): stop sybil double-importing UnitsMatrix under a combined pytest run - #887

Merged
nstarman merged 3 commits into
GalacticDynamics:mainfrom
nstarman:claude/issue-881-fix-7ae8ba
Aug 16, 2026
Merged

fix(linalg): stop sybil double-importing UnitsMatrix under a combined pytest run#887
nstarman merged 3 commits into
GalacticDynamics:mainfrom
nstarman:claude/issue-881-fix-7ae8ba

Conversation

@nstarman

Copy link
Copy Markdown
Contributor

Summary

Fixes #881.

Sybil computes a doctest module's import name by walking up through __init__.py directories, so at the unxts PEP 420 namespace boundary it imports packages/unxts.linalg/src doctests as linalg.* instead of unxts.linalg.*. Unlike unxts.interop.gala / unxts.interop.xarray / unxts.hypothesis — which hit this same mechanism but fail loudly because their leaf name collides with an installed library — linalg has no installed package to collide with, so the mis-import silently "succeeds": it builds a second, wrongly-named module tree alongside the real unxts.linalg one, duplicating any class defined there (e.g. UnitsMatrix). Whichever copy a doctest sees is a !=-different class from the copy the rest of the pytest session imports, so isinstance checks and plum's return-type conversion both fail wherever a -> UnitsMatrix dispatch (like unit_of) is exercised in the same session as the package's own doctests — i.e. pytest packages/unxts.linalg (src + tests together).

Confirmed the mechanism directly: a debug test dumping sys.modules mid-run shows two live UnitsMatrix classes with different id()s, one under linalg._src._units_matrix (sybil's leaf-based name) and one under unxts.linalg._src._units_matrix (the real one).

The repo already has the fix for this exact class of bug — conftest.py's _DOCTEST_MODULE_SRC skip-list plus a namespace-aware --doctest-modules --import-mode=importlib CI step, applied for gala/xarray/hypothesis. This PR applies the same fix to unxts.linalg.

Changes

  • conftest.py: add packages/unxts.linalg/src/ to _DOCTEST_MODULE_SRC so sybil skips collecting its doctests under the wrong module name (in any combined session, not just CI); broadened the explanatory comment to cover the silent-duplicate-class failure mode, not just the loud import-collision one.
  • .github/workflows/ci.yml: switch the unxts-linalg job's src-doctest step to the same --doctest-modules -o addopts="--import-mode=importlib" -o consider_namespace_packages=true -o doctest_optionflags="ELLIPSIS NORMALIZE_WHITESPACE" invocation already used for gala/xarray/hypothesis, so src doctests keep running under the correct module name. (The job's previous split-invocation comment was a workaround for CI specifically; it didn't help local combined runs, which is what plum return conversion for UnitsMatrix fails under a combined pytest session (Cannot convert UnitsMatrix to UnitsMatrix) #881 reports.)

Test plan

  • pytest packages/unxts.linalg (src + tests together, the exact repro from plum return conversion for UnitsMatrix fails under a combined pytest session (Cannot convert UnitsMatrix to UnitsMatrix) #881) — was 8 failed, now 374 passed
  • pytest packages/unxts.linalg/src --doctest-modules -o addopts="--import-mode=importlib" -o consider_namespace_packages=true -o doctest_optionflags="ELLIPSIS NORMALIZE_WHITESPACE" (new CI step) — 42 passed, same doctest-bearing functions/classes as before, just one item per docstring instead of per sybil example-region
  • pytest packages/unxts.linalg/tests — 262 passed, unaffected
  • pytest packages/unxts.linalg src/unxt (sanity check against the rest of the tree) — 2397 passed
  • pre-commit hooks (ruff, pyright/ty/mypy typing guards, yaml validation, etc.) — all passed

🤖 Generated with Claude Code

@nstarman
nstarman requested a review from a team as a code owner August 15, 2026 08:23
Copilot AI lite review requested due to automatic review settings August 15, 2026 08:23

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 fixes a Sybil/pytest namespace-package edge case where doctests in packages/unxts.linalg/src can be imported under an incorrect leaf module name (linalg.*), causing duplicate module trees and type identity mismatches (e.g., UnitsMatrix) in combined pytest runs.

Changes:

  • Skips Sybil doctest collection for packages/unxts.linalg/src/ via the existing _DOCTEST_MODULE_SRC mechanism to prevent mis-import/double-import during combined sessions.
  • Aligns the unxts-linalg CI job’s src-doctest invocation with other unxts.* namespace packages by running pytest doctests with --import-mode=importlib and consider_namespace_packages=true.

Reviewed changes

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

File Description
conftest.py Adds unxts.linalg to the Sybil doctest skip list to avoid leaf-based mis-import under PEP 420.
.github/workflows/ci.yml Updates the unxts-linalg CI job to run src doctests via pytest’s namespace-aware doctest collection settings.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread conftest.py Outdated
@nstarman nstarman added this to the v2.0.x milestone Aug 15, 2026
nstarman and others added 3 commits August 15, 2026 10:44
… pytest run

Sybil computes a doctest module's import name by walking up through
`__init__.py` directories, so at the `unxts` PEP 420 namespace boundary it
imports `packages/unxts.linalg/src` doctests as `linalg.*` instead of
`unxts.linalg.*`. Unlike gala/xarray/hypothesis, `linalg` has no installed
package to collide with, so the mis-import "succeeds" -- silently building a
second module tree and duplicating classes like `UnitsMatrix`. Whichever
copy a doctest sees is `!=` the copy the rest of the session imports, so
`isinstance` checks and plum's return-type conversion both fail wherever a
`-> UnitsMatrix` dispatch is exercised in the same session as its own
doctests (`pytest packages/unxts.linalg`).

Add `unxts.linalg/src` to the existing `_DOCTEST_MODULE_SRC` skip list (same
fix already applied for gala/xarray/hypothesis) and move its CI job onto the
namespace-aware `--doctest-modules --import-mode=importlib` invocation used
by those packages, so src doctests still run, just under the correct module
name.

Fixes GalacticDynamics#881

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Trim the unxts.linalg explanation added for GalacticDynamics#881 down to the one fact
that isn't already covered by the surrounding paragraph, and drop the
"!=`-different classes" phrasing a review flagged as suggesting value
inequality rather than the actual identity mismatch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…solves correctly

GalacticDynamics#880 shipped this test pre-xfailed pending the fix in this branch; it
now passes under the same combined pytest session the xfail called out.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@nstarman
nstarman force-pushed the claude/issue-881-fix-7ae8ba branch from e40a378 to 327a382 Compare August 15, 2026 08:47
@github-actions github-actions Bot added 👷 Add / update CI build system Add or update CI build system. 🔧 Add / update configuration Add or update configuration files. 🧩 unxts-linalg Issues/PRs affecting the unxts.linalg namespace package labels Aug 15, 2026
@codecov

codecov Bot commented Aug 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.96%. Comparing base (94bb0f4) to head (327a382).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #887      +/-   ##
==========================================
+ Coverage   99.82%   99.96%   +0.13%     
==========================================
  Files          84       46      -38     
  Lines        3998     2693    -1305     
  Branches      311      162     -149     
==========================================
- Hits         3991     2692    -1299     
+ Misses          3        0       -3     
+ Partials        4        1       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nstarman
nstarman merged commit 8b8a563 into GalacticDynamics:main Aug 16, 2026
56 of 58 checks passed
@nstarman
nstarman deleted the claude/issue-881-fix-7ae8ba branch August 16, 2026 15:46
nstarman added a commit that referenced this pull request Aug 17, 2026
…ouble-importing UnitsMatrix under a combined pytest run) (#890)

* Backport PR #887: fix(linalg): stop sybil double-importing UnitsMatrix under a combined pytest run
* fix(test): ignore astropy's XDG config-dir race warning under pytest-xdist

pytest-xdist workers race to create ~/.astropy/config on first astropy
import; whichever worker loses the race gets an AstropyUserWarning that
pytest's filterwarnings=error turns into a collection-crashing error,
producing "Different tests were collected between gw2 and gw3" (fixed
in PR #883's -n logical --dist=loadfile parallelization).

Filter category is UserWarning, not astropy's own AstropyUserWarning
class: resolving that class name requires importing astropy, which can
re-trigger the same warning before the ignore rule itself is applied.

Co-authored-by: Nathaniel Starkman <nstarman@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

👷 Add / update CI build system Add or update CI build system. 🔧 Add / update configuration Add or update configuration files. 🧩 unxts-linalg Issues/PRs affecting the unxts.linalg namespace package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

plum return conversion for UnitsMatrix fails under a combined pytest session (Cannot convert UnitsMatrix to UnitsMatrix)

2 participants