Skip to content

WIP: importor skip#2650

Draft
paul-nechifor wants to merge 1 commit into
mainfrom
paul/fix/importorskip
Draft

WIP: importor skip#2650
paul-nechifor wants to merge 1 commit into
mainfrom
paul/fix/importorskip

Conversation

@paul-nechifor

Copy link
Copy Markdown
Contributor

Problem

Closes DIM-XXX

Solution

How to Test

Contributor License Agreement

  • I have read and approved the CLA.

@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 11 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
dimos/codebase_checks/test_no_importorskip.py 71.79% 8 Missing and 3 partials ⚠️
@@            Coverage Diff             @@
##             main    #2650      +/-   ##
==========================================
+ Coverage   71.10%   71.26%   +0.15%     
==========================================
  Files         897      895       -2     
  Lines       80290    80119     -171     
  Branches     7183     7192       +9     
==========================================
+ Hits        57089    57093       +4     
+ Misses      21319    21140     -179     
- Partials     1882     1886       +4     
Flag Coverage Δ
OS-ubuntu-24.04-arm 64.73% <75.00%> (+1.21%) ⬆️
OS-ubuntu-latest 66.38% <75.00%> (+0.14%) ⬆️
Py-3.10 66.37% <75.00%> (+0.14%) ⬆️
Py-3.11 66.37% <75.00%> (+0.14%) ⬆️
Py-3.12 66.37% <75.00%> (+0.14%) ⬆️
Py-3.13 66.38% <75.00%> (+0.15%) ⬆️
Py-3.14 66.39% <75.00%> (+0.15%) ⬆️
Py-3.14t 66.38% <75.00%> (+0.15%) ⬆️
SelfHosted-Large 30.15% <27.27%> (+0.05%) ⬆️
SelfHosted-Linux 37.55% <27.27%> (+0.06%) ⬆️
SelfHosted-macOS 36.37% <27.27%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
dimos/hardware/manipulators/openarm/test_driver.py 98.55% <100.00%> (ø)
dimos/manipulation/visualization/viser/conftest.py 100.00% <100.00%> (ø)
...anipulation/visualization/viser/test_gui_status.py 100.00% <ø> (ø)
...ation/visualization/viser/test_operation_worker.py 98.25% <ø> (-0.02%) ⬇️
...on/visualization/viser/test_viser_visualization.py 97.84% <ø> (-0.01%) ⬇️
...n/visualization/viser/test_visualizer_lifecycle.py 98.17% <ø> (-0.01%) ⬇️
dimos/memory2/codecs/test_codecs.py 87.50% <ø> (-0.28%) ⬇️
...s/perception/fiducial/test_fixture_verification.py 98.48% <ø> (-0.02%) ⬇️
...on/fiducial/test_marker_detection_stream_module.py 100.00% <ø> (ø)
dimos/perception/fiducial/test_marker_pose.py 100.00% <ø> (ø)
... and 4 more

... and 8 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR enforces a no-pytest.importorskip policy across the test suite: every existing use of importorskip is converted to either a direct module-level import (for packages that are always installed via the tests dependency group) or an explicit collection exclusion (--ignore in CI or collect_ignore in a new conftest.py). A new test_no_importorskip.py codebase check prevents any future regression by failing the test suite if the pattern reappears.

  • Packages always in the tests group (mujoco, python-can, cv2.aruco via dimos[apriltag], turbojpeg via base deps) are converted to bare module-level imports; tests that were gracefully skipped before will now fail loudly at collection time if a dependency is missing.
  • Native extension packages not in the standard tests group (dimos_mls_planner, dimos_voxel_ray_tracing) are handled by adding --ignore flags to every CI job and a new conftest.py covers the viser tests on aarch64 where the wheel isn't built.

Confidence Score: 4/5

Safe to merge; all converted imports are backed by verified test-group dependencies, and the new enforcement test correctly self-excludes.

Every converted importorskip is either for a package present in the tests dependency group (mujoco, python-can, PyTurboJPEG, opencv-contrib-python via dimos[apriltag]) or is paired with a matching --ignore / collect_ignore guard. The new test_no_importorskip.py codebase check closes the loop cleanly. The one open question is whether adding --ignore to self_hosted_large permanently removes test coverage that should actually run on that runner once native extensions are built there.

.github/workflows/ci.yml — the self_hosted_large job now ignores dimos/mapping/ray_tracing and dimos/navigation/nav_3d/mls_planner unconditionally; confirm those native packages are not (and will not be) available on that runner.

Important Files Changed

Filename Overview
dimos/codebase_checks/test_no_importorskip.py New enforcement test: scans all .py files under dimos/ for "importorskip" and fails if any are found. Self-exclusion logic is correct, but _is_ignored_dir(dirpath) is redundant because dirnames[:] filtering already prevents os.walk from entering those directories.
.github/workflows/ci.yml Adds --ignore=dimos/mapping/ray_tracing and --ignore=dimos/navigation/nav_3d/mls_planner to all three CI jobs including self_hosted_large; those tests will not run even if the native packages are eventually available on the large runner.
dimos/simulation/engines/test_robot_sim_binding.py Replaces importorskip("mujoco") with direct import; mujoco is in the tests dependency group so collection works in CI. The pytestmark = pytest.mark.mujoco marker continues to prevent these tests from running in non-mujoco jobs.
dimos/manipulation/visualization/viser/conftest.py New conftest.py with collect_ignore list for aarch64 where viser[urdf] has no wheel; correctly mirrors the platform condition in pyproject.toml and the skipif_aarch64 convention in the root conftest.
dimos/protocol/pubsub/test_registry.py Moves turbojpeg import to module level; PyTurboJPEG is a core dimos dependency so the import always succeeds. The runtime skip for missing libturbojpeg.so is preserved via pytest.skip() inside the test function.
dimos/hardware/manipulators/openarm/test_driver.py Replaces importorskip("can") with direct import; python-can is in the tests dependency group so this is safe in CI.
dimos/navigation/nav_3d/mls_planner/test_transformer.py Removes importorskip("dimos_mls_planner") and the now-unused pytest import; CI ignores this whole directory, so collection of this file is skipped in all CI jobs.
dimos/memory2/codecs/test_codecs.py Removes redundant importorskip("turbojpeg") and local JpegCodec re-import inside test body; JpegCodec was already imported at module level, and turbojpeg is a core dep.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[pytest collect] --> B{package available?}
    B -->|always in tests group\nmujoco, python-can, cv2.aruco, turbojpeg| C[Direct import at module level\nCollection succeeds]
    B -->|native extension\ndimos_mls_planner\ndimos_voxel_ray_tracing| D[CI --ignore flag\nDirectory skipped entirely]
    B -->|platform-conditional\nviser on aarch64| E[conftest.py collect_ignore\nFiles excluded on aarch64]

    C --> F{marker filter}
    F -->|pytestmark = mujoco\nnot in default run| G[Test skipped by marker]
    F -->|no restricting marker| H[Test runs]

    D --> I[Never collected in CI]
    E --> J[Never collected on aarch64]

    K[test_no_importorskip.py] -->|fails build if any .py\ncontains importorskip| L[Policy enforced]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[pytest collect] --> B{package available?}
    B -->|always in tests group\nmujoco, python-can, cv2.aruco, turbojpeg| C[Direct import at module level\nCollection succeeds]
    B -->|native extension\ndimos_mls_planner\ndimos_voxel_ray_tracing| D[CI --ignore flag\nDirectory skipped entirely]
    B -->|platform-conditional\nviser on aarch64| E[conftest.py collect_ignore\nFiles excluded on aarch64]

    C --> F{marker filter}
    F -->|pytestmark = mujoco\nnot in default run| G[Test skipped by marker]
    F -->|no restricting marker| H[Test runs]

    D --> I[Never collected in CI]
    E --> J[Never collected on aarch64]

    K[test_no_importorskip.py] -->|fails build if any .py\ncontains importorskip| L[Policy enforced]
Loading

Reviews (1): Last reviewed commit: "importor skip" | Re-trigger Greptile

Comment on lines +49 to +53
if _is_ignored_dir(dirpath):
continue

for fname in filenames:
if not fname.endswith(".py"):

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.

P2 Redundant _is_ignored_dir(dirpath) guard

The dirnames[:] = [d for d in dirnames if d not in IGNORED_DIRS] mutation on the line above already prevents os.walk from ever descending into an ignored directory, so dirpath will never contain a component from IGNORED_DIRS during the traversal. The if _is_ignored_dir(dirpath): continue branch is therefore unreachable for any dirpath below dimos_dir and can be safely removed to avoid misleading readers into thinking there are two independent layers of filtering.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread .github/workflows/ci.yml
env:
DISPLAY: ":0"
run: uv run pytest --cov=dimos/ --junitxml=junit.xml -m self_hosted_large
run: uv run pytest --ignore=dimos/mapping/ray_tracing --ignore=dimos/navigation/nav_3d/mls_planner --cov=dimos/ --junitxml=junit.xml -m self_hosted_large

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.

P2 --ignore applied to self_hosted_large may permanently suppress coverage

self_hosted_large is the high-memory runner intended for heavier workloads. If dimos_mls_planner or dimos_voxel_ray_tracing are — or ever become — available on that runner (e.g. as a compiled native artifact cached in the runner image), adding the same --ignore flags here means those test directories will never execute there either. A broken change to the ray-tracing or MLS-planner code would not be caught by any CI job. Consider whether the self_hosted_large runner should build and run those suites instead of ignoring them.


from dimos.constants import DIMOS_PROJECT_ROOT

PATTERN = "importorskip"

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.

P2 Pattern is a bare substring — matches comments and docstrings too

PATTERN = "importorskip" matches any occurrence of the string, including lines like # Do not use importorskip here or a docstring explaining the policy. That's probably the desired strictness (zero-tolerance), but a comment explaining the intent would help reviewers who might otherwise try to "work around" the check with a comment. Worth a one-line note in the constant definition.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I would recommend against this. This will make it more difficult for downstream to test dimos. Instead, I suggest paying more attention to codecov (the CI checks should all be in place now).

For release, we added the error-on-skips to ensure we do test everything before a release (should be an automated step soon), so any damage caused by an importorskip is short term.

As prior art, we use this in several places in aiohttp for similar reasons:
https://github.com/search?q=repo%3Aaio-libs%2Faiohttp%20importorskip&type=code

I also suspect that people will see the importskip being banned in future, and then just use the less preferred try/except pattern to achieve the same result..

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.

2 participants