From 3d55a16c916d1b89d9d4226d57dcaa11338b04a1 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 16 May 2025 19:56:33 +0200 Subject: [PATCH] [ty] Migrate the namespace package module resolver tests to mdtests (#18133) Co-authored-by: Alex Waygood --- .../resources/mdtest/import/namespace.md | 107 ++++++++++++++++++ .../src/module_resolver/resolver.rs | 95 ---------------- 2 files changed, 107 insertions(+), 95 deletions(-) create mode 100644 crates/ty_python_semantic/resources/mdtest/import/namespace.md diff --git a/crates/ty_python_semantic/resources/mdtest/import/namespace.md b/crates/ty_python_semantic/resources/mdtest/import/namespace.md new file mode 100644 index 0000000000..91dff55c58 --- /dev/null +++ b/crates/ty_python_semantic/resources/mdtest/import/namespace.md @@ -0,0 +1,107 @@ +# Namespace package + +## Basic namespace package + +```toml +[environment] +python = "/.venv" +``` + +`parent/child/one.py`: + +```py +one = 1 +``` + +`/.venv//parent/child/two.py`: + +```py +two = 2 +``` + +`main.py`: + +```py +import parent.child.one +import parent.child.two +``` + +`from.py` + +```py +# TODO: This should not be an error +from parent.child import one, two # error: [unresolved-import] +``` + +## Regular package in namespace package + +```toml +[environment] +python = "/.venv" +``` + +An adapted test case from the +[PEP420 examples](https://peps.python.org/pep-0420/#nested-namespace-packages). The +`src/parent/child` package is a regular package. Therefore, `site_packages/parent/child/two.py` +should not be resolved. + +```ignore +src + parent + child + __init__.py + one.py +.venv/site-packages + parent + child + two.py +``` + +`parent/child/__init__.py`: + +```py +``` + +`parent/child/one.py`: + +```py +one = 1 +``` + +`/.venv//parent/child/two.py`: + +```py +two = 2 +``` + +`main.py`: + +```py +import parent.child.one + +import parent.child.two # error: [unresolved-import] +``` + +## Priority between file and identically named namespace package + +If there's a namespace package with the same name as a module, the module takes precedence. + +`foo.py`: + +```py +x = "module" +``` + +`foo/bar.py`: + +```py +x = "namespace" +``` + +```py +from foo import x + +reveal_type(x) # revealed: Unknown | Literal["module"] + +import foo.bar # error: [unresolved-import] +``` diff --git a/crates/ty_python_semantic/src/module_resolver/resolver.rs b/crates/ty_python_semantic/src/module_resolver/resolver.rs index 766d4f3d15..5f4aa1e197 100644 --- a/crates/ty_python_semantic/src/module_resolver/resolver.rs +++ b/crates/ty_python_semantic/src/module_resolver/resolver.rs @@ -1288,25 +1288,6 @@ mod tests { ); } - #[test] - fn single_file_takes_priority_over_namespace_package() { - //const SRC: &[FileSpec] = &[("foo.py", "x = 1")]; - const SRC: &[FileSpec] = &[("foo.py", "x = 1"), ("foo/bar.py", "x = 2")]; - - let TestCase { db, src, .. } = TestCaseBuilder::new().with_src_files(SRC).build(); - - let foo_module_name = ModuleName::new_static("foo").unwrap(); - let foo_bar_module_name = ModuleName::new_static("foo.bar").unwrap(); - - // `foo.py` takes priority over the `foo` namespace package - let foo_module = resolve_module(&db, &foo_module_name).unwrap(); - assert_eq!(foo_module.file().path(&db), &src.join("foo.py")); - - // `foo.bar` isn't recognised as a module - let foo_bar_module = resolve_module(&db, &foo_bar_module_name); - assert_eq!(foo_bar_module, None); - } - #[test] fn typing_stub_over_module() { const SRC: &[FileSpec] = &[("foo.py", "print('Hello, world!')"), ("foo.pyi", "x: int")]; @@ -1349,82 +1330,6 @@ mod tests { ); } - #[test] - fn namespace_package() { - // From [PEP420](https://peps.python.org/pep-0420/#nested-namespace-packages). - // But uses `src` for `project1` and `site-packages` for `project2`. - // ``` - // src - // parent - // child - // one.py - // site_packages - // parent - // child - // two.py - // ``` - let TestCase { - db, - src, - site_packages, - .. - } = TestCaseBuilder::new() - .with_src_files(&[("parent/child/one.py", "print('Hello, world!')")]) - .with_site_packages_files(&[("parent/child/two.py", "print('Hello, world!')")]) - .build(); - - let one_module_name = ModuleName::new_static("parent.child.one").unwrap(); - let one_module_path = FilePath::System(src.join("parent/child/one.py")); - assert_eq!( - resolve_module(&db, &one_module_name), - path_to_module(&db, &one_module_path) - ); - - let two_module_name = ModuleName::new_static("parent.child.two").unwrap(); - let two_module_path = FilePath::System(site_packages.join("parent/child/two.py")); - assert_eq!( - resolve_module(&db, &two_module_name), - path_to_module(&db, &two_module_path) - ); - } - - #[test] - fn regular_package_in_namespace_package() { - // Adopted test case from the [PEP420 examples](https://peps.python.org/pep-0420/#nested-namespace-packages). - // The `src/parent/child` package is a regular package. Therefore, `site_packages/parent/child/two.py` should not be resolved. - // ``` - // src - // parent - // child - // one.py - // site_packages - // parent - // child - // two.py - // ``` - const SRC: &[FileSpec] = &[ - ("parent/child/__init__.py", "print('Hello, world!')"), - ("parent/child/one.py", "print('Hello, world!')"), - ]; - - const SITE_PACKAGES: &[FileSpec] = &[("parent/child/two.py", "print('Hello, world!')")]; - - let TestCase { db, src, .. } = TestCaseBuilder::new() - .with_src_files(SRC) - .with_site_packages_files(SITE_PACKAGES) - .build(); - - let one_module_path = FilePath::System(src.join("parent/child/one.py")); - let one_module_name = - resolve_module(&db, &ModuleName::new_static("parent.child.one").unwrap()); - assert_eq!(one_module_name, path_to_module(&db, &one_module_path)); - - assert_eq!( - None, - resolve_module(&db, &ModuleName::new_static("parent.child.two").unwrap()) - ); - } - #[test] fn module_search_path_priority() { let TestCase {