Repository navigation
interpreter: canonicalize when initializing search paths dynamically - #8299
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughDynamic standard-library paths are canonicalized before configuring the standard-library directory and module search paths, with fallback handling and Windows path-prefix normalization. ChangesDynamic stdlib path normalization
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/interpreter.rs`:
- Around line 65-72: Update the path-string closure around the local variable s
to avoid a let-and-return pattern on non-Windows builds: keep the Windows
strip_prefix handling, but defer to_string_lossy().into_owned() until the final
return expression so the conversion is performed once without duplicating
platform-specific logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: a8265471-32b9-4925-b0a9-ca7a37610390
⛔ Files ignored due to path filters (1)
Lib/test/test_unittest/test_program.pyis excluded by!Lib/**
📒 Files selected for processing (1)
src/interpreter.rs
📦 Library DependenciesThe following Lib/ modules were modified. Here are their dependencies: [ ] lib: cpython/Lib/unittest dependencies:
dependent tests: (408 tests)
Legend:
|
Dual-Root Mismatch in RustPython:
Unlike CPython, RustPython manages the standard library
in two separate locations in the workspace:
- Workspace 'Lib/': Contains the test suite ('Lib/test/...') and
standard library files.
- crates/pylib/Lib/: A helper directory used for packaging.
'crates/pylib/Lib' is a symlink pointing to the real workspace '../../Lib/'.
Runtime Directory Discrepancy:
- 'sys.path' contains 'crates/pylib/Lib' (the path to the symlink).
- Thus, when 'test.support' is imported, its '__file__' is resolved relative
to the symlink: '/opt/RustPython/crates/pylib/Lib/test/support/__init__.py'.
- Consequently, 'STDLIB_DIR' resolves to the symlink root:
'/opt/RustPython/crates/pylib/Lib'.
- However, since 'test_program.py' is executed directly from the workspace,
its 'pkg_dir' is: '/opt/RustPython/Lib/test/test_unittest/testmock'.
- When 'os.path.relpath(pkg_dir, top_dir)' is called:
---
os.path.relpath(
"/opt/RustPython/Lib/test/test_unittest/testmock",
"/opt/RustPython/crates/pylib/Lib"
)
# Result: "../../../Lib/test/test_unittest/testmock"
---
Because the relative path starts with '..', the assertion fails.
Assisted-by: Gemini
youknowone
left a comment
There was a problem hiding this comment.
catching good point, thanks!
…8299) Dual-Root Mismatch in RustPython: Unlike CPython, RustPython manages the standard library in two separate locations in the workspace: - Workspace 'Lib/': Contains the test suite ('Lib/test/...') and standard library files. - crates/pylib/Lib/: A helper directory used for packaging. 'crates/pylib/Lib' is a symlink pointing to the real workspace '../../Lib/'. Runtime Directory Discrepancy: - 'sys.path' contains 'crates/pylib/Lib' (the path to the symlink). - Thus, when 'test.support' is imported, its '__file__' is resolved relative to the symlink: '/opt/RustPython/crates/pylib/Lib/test/support/__init__.py'. - Consequently, 'STDLIB_DIR' resolves to the symlink root: '/opt/RustPython/crates/pylib/Lib'. - However, since 'test_program.py' is executed directly from the workspace, its 'pkg_dir' is: '/opt/RustPython/Lib/test/test_unittest/testmock'. - When 'os.path.relpath(pkg_dir, top_dir)' is called: --- os.path.relpath( "/opt/RustPython/Lib/test/test_unittest/testmock", "/opt/RustPython/crates/pylib/Lib" ) # Result: "../../../Lib/test/test_unittest/testmock" --- Because the relative path starts with '..', the assertion fails. Assisted-by: Gemini
RustPython Test Discovery Path Mismatch: Root Cause and Solution Comparison
This document provides a detailed analysis of the
AssertionError: Path must be within the projectfailure during unittest discovery in RustPython, comparing two approaches to fix it.1. Root Cause Analysis
The Error Scenario
When executing the test suite with:
unittest.loaderencounters an assertion failure during test discovery:The Mechanism
Unittest Loader Constraint:
CPython's
unittestlibrary asserts that any discovered test package (start_dir) must reside inside the project's top-level directory (top_level_dir).It checks this by computing the relative path and verifying it doesn't navigate upwards:
Dual-Root Mismatch in RustPython:
Unlike CPython, RustPython manages the standard library in two separate locations in the workspace:
Lib/: Contains the test suite (Lib/test/...) and standard library files.crates/pylib/Lib/: A helper directory used for packaging.crates/pylib/Libis a symlink pointing to the real workspace../../Lib/.Runtime Directory Discrepancy:
sys.pathcontainscrates/pylib/Lib(the path to the symlink).test.supportis imported, its__file__is resolved relative to the symlink:/home/lsahn/projects/oss/RustPython/crates/pylib/Lib/test/support/__init__.py.STDLIB_DIRresolves to the symlink root:/home/lsahn/projects/oss/RustPython/crates/pylib/Lib.test_program.pyis executed directly from the workspace, itspkg_diris:/home/lsahn/projects/oss/RustPython/Lib/test/test_unittest/testmock.os.path.relpath(pkg_dir, top_dir)is called:.., the assertion fails.2. Comparison of Solutions
Solution 1: Python-Level Fix (Modifying
Lib/test/support/__init__.py)This approach intercepts the path discrepancy within the test framework itself.
Inside
load_package_testsinLib/test/support/__init__.py, check ifpkg_dirfalls outsideSTDLIB_DIR(using.startswith('..')). If so, trace up frompkg_dirto dynamically find the standard library root containing the test package.Lib/test/creates merge conflicts and complicates maintenance.sys.path.Solution 2: Rust-Level Fix (Modifying
src/interpreter.rs- Recommended)This approach resolves the symlink at the interpreter level when building standard library search paths.
When initializing search paths dynamically in
setup_dynamic_stdlibusingcollect_stdlib_paths(), runstd::fs::canonicalizeon the paths. This resolves thecrates/pylib/Libsymlink to its target/home/lsahn/projects/oss/RustPython/Libbefore adding it tosys.path.Lib/testfiles pristine and 100% compatible with upstream CPython.__file__always refers to canonical paths, preventing path mismatches across the entire runtime environment.Why Did Only This Specific Test Case Fail?
This document explains why the path resolution mismatch and subsequent
AssertionErroronly affected a tiny subset of tests (specifically unittest discovery withintest_unittest), while other tests involving symlinks ran successfully.1. The Normal Case: Why Most Tests Succeed
Most standard library tests (e.g.,
test_dict.py,test_bytes.py) do not fail because they do not trigger path verification:unittest.loader.discover().unittest discovercommands are run from the CLI (e.g.,rustpython -m unittest discover -s Lib/test), both the start directory (start_dir) and top-level directory (top_level_dir) reside under the same folder (Lib/). Since there is no cross-referencing between different root directories,os.path.relpath()never returns a path starting with...2. The Failure Case: The Mismatch Scenario
The failure in
testSelectedTestNamesFunctionalTestoccurred because it met a highly specific set of conditions:Sub-package Hook (
testmock):The
testmocksub-package defines a customload_testshook that delegates to a shared helper intest.support:Hardcoded
STDLIB_DIRinload_package_tests:The helper in
test.supportinvokes discovery, hardcoding the project root toSTDLIB_DIR:Dual-Root Mismatch:
Because
test.supportis imported from the packaged stdlib directory, while the test file itself runs from the workspace directory:pkg_dir(start directory) resolves to:.../Lib/test/test_unittest/testmock(workspace realpath).top_dir(top-level directory) resolves to:.../crates/pylib/Lib(symlink path).Because
loader.discoverwas passed two paths belonging to different directories (one starting withLib/and the other withcrates/pylib/Lib/),os.path.relpathcomputed a relative path that navigated upwards (beginning with..). This directly triggered the assertion:assert not _relpath.startswith('..').Summary
The error only surfaces when a test package runs from the workspace
Libdirectory but delegates its sub-test discovery totest.support(imported fromcrates/pylib/Lib), forcing the unittest discoverer to compare paths across two different filesystem roots.Summary by CodeRabbit
\\?\) path prefixes when present.