Repository: astral-sh/ruff
Pull request #18137: [ty] Support `import <namespace>` and `from <namespace> import module`
Author: login: MichaReiser
Labels: name: ty
description: Multi-file analysis & type inference
Created: 2025-05-16T15:12:27Z | Merged: 2025-05-21T07:28:33Z

## Summary

The module resolver incorrectly returned `None` if a module name resolves to a namespace package (it did correctly handle the case where a module name resolves to a file inside a namespace package).

Supporting this requires a smaller refactor because `Module` assumed that `file` and `search_path` are always known. However, neither are present for a namespace package (it doesn't resolve to a file AND the package can exist on multiple search paths).



Fixes https://github.com/astral-sh/ty/issues/375
Fixes https://github.com/astral-sh/ty/issues/363

## Test plan

Added regression tests. I verified that the imports in the linked issues resolve successfully.

## Ecosystem review

* `optuna`: Correct, [`auto_generated`](https://github.com/optuna/optuna/tree/master/optuna/storages/_grpc/auto_generated) is a namespace package
* `rotki`: Correct, the project has a [`packaging`](https://github.com/rotki/rotki/tree/develop/packaging?rgh-link-date=2025-05-16T17%3A27%3A03Z) folder. It doesn't contain any python code but it isn't wrong for ty to pick it up as a namespace package.
* ~~`psycopg`~~: All the code is in `psycopg/psycopg` (it's a src layout but the `src` folder is called `psycopg`). We weren't able to resolve any imports before. We now resolve `psycopg` as a namespace package which is *correct* from a module resolution point. The solution here is to change how we detect `src.root` or that they change their configuration to set `src.root`
* [`rclip`](https://github.com/yurijmikhalevich/rclip/tree/main/rclip): Is a namespace package and we are now able to resolve the imports 
* `dd-trace-py`: `benchmarks` is a namespace package and we're now able to resolve imports. They also use other namespace packages that now resolve correctly
* `scipy`: They use submodules for some of the modules in [`_lib`](https://github.com/scipy/scipy/tree/main/scipy/_lib) but they point to the [project root](https://github.com/data-apis/array-api-compat/tree/8005d6d02c0f1717881de37a710871bb955eb5cd) and not the package folder? We now recognize them as namespace packages. 


Unsure: 

**`schema_salad`**: 

The relevant lines are:

```py
import ruamel.yaml
from ruamel.yaml.comments import CommentedBase, CommentedMap, CommentedSeq

def _add_lc_filename(r: ruamel.yaml.comments.CommentedBase, source: AnyStr) -> None:
```

`ruamel` is a namespace package, `ruamel.yaml` is a regular package. 

Before: We inferred `Unknown` for `ruamel` and `yaml`
Now: We infer `ruamel.yaml` but it seems we don't resolve the `comments.py` module?

I think this is unrelated to my changes.

**cwltool**: Same as `schema_salad`


Diff:
diff --git a/crates/ruff_graph/src/resolver.rs b/crates/ruff_graph/src/resolver.rs
index 8ac228a6b18ab..baf43c71c9eb5 100644
--- a/crates/ruff_graph/src/resolver.rs
+++ b/crates/ruff_graph/src/resolver.rs
@@ -19,19 +19,20 @@ impl<'a> Resolver<'a> {
     pub(crate) fn resolve(&self, import: CollectedImport) -> Option<&'a FilePath> {
         match import {
             CollectedImport::Import(import) => {
-                resolve_module(self.db, &import).map(|module| module.file().path(self.db))
+                let module = resolve_module(self.db, &import)?;
+                Some(module.file()?.path(self.db))
             }
             CollectedImport::ImportFrom(import) => {
                 // Attempt to resolve the member (e.g., given `from foo import bar`, look for `foo.bar`).
                 let parent = import.parent();
 
-                resolve_module(self.db, &import)
-                    .map(|module| module.file().path(self.db))
-                    .or_else(|| {
-                        // Attempt to resolve the module (e.g., given `from foo import bar`, look for `foo`).
+                let module = resolve_module(self.db, &import).or_else(|| {
+                    // Attempt to resolve the module (e.g., given `from foo import bar`, look for `foo`).
 
-                        resolve_module(self.db, &parent?).map(|module| module.file().path(self.db))
-                    })
+                    resolve_module(self.db, &parent?)
+                })?;
+
+                Some(module.file()?.path(self.db))
             }
         }
     }
diff --git a/crates/ty/tests/file_watching.rs b/crates/ty/tests/file_watching.rs
index 45eff5d307cf8..c8f3a186b0040 100644
--- a/crates/ty/tests/file_watching.rs
+++ b/crates/ty/tests/file_watching.rs
@@ -1444,13 +1444,11 @@ mod unix {
         )
         .expect("Expected bar.baz to exist in site-packages.");
         let baz_project = case.project_path("bar/baz.py");
+        let baz_file = baz.file().unwrap();
 
+        assert_eq!(source_text(case.db(), baz_file).as_str(), "def baz(): ...");
         assert_eq!(
-            source_text(case.db(), baz.file()).as_str(),
-            "def baz(): ..."
-        );
-        assert_eq!(
-            baz.file().path(case.db()).as_system_path(),
+            baz_file.path(case.db()).as_system_path(),
             Some(&*baz_project)
         );
 
@@ -1465,7 +1463,7 @@ mod unix {
         case.apply_changes(changes);
 
         assert_eq!(
-            source_text(case.db(), baz.file()).as_str(),
+            source_text(case.db(), baz_file).as_str(),
             "def baz(): print('Version 2')"
         );
 
@@ -1478,7 +1476,7 @@ mod unix {
         case.apply_changes(changes);
 
         assert_eq!(
-            source_text(case.db(), baz.file()).as_str(),
+            source_text(case.db(), baz_file).as_str(),
             "def baz(): print('Version 3')"
         );
 
@@ -1524,6 +1522,7 @@ mod unix {
             &ModuleName::new_static("bar.baz").unwrap(),
         )
         .expect("Expected bar.baz to exist in site-packages.");
+        let baz_file = baz.file().unwrap();
         let bar_baz = case.project_path("bar/baz.py");
 
         let patched_bar_baz = case.project_path("patched/bar/baz.py");
@@ -1534,11 +1533,8 @@ mod unix {
             "def baz(): ..."
         );
 
-        assert_eq!(
-            source_text(case.db(), baz.file()).as_str(),
-            "def baz(): ..."
-        );
-        assert_eq!(baz.file().path(case.db()).as_system_path(), Some(&*bar_baz));
+        assert_eq!(source_text(case.db(), baz_file).as_str(), "def baz(): ...");
+        assert_eq!(baz_file.path(case.db()).as_system_path(), Some(&*bar_baz));
 
         case.assert_indexed_project_files([patched_bar_baz_file]);
 
@@ -1567,7 +1563,7 @@ mod unix {
         let patched_baz_text = source_text(case.db(), patched_bar_baz_file);
         let did_update_patched_baz = patched_baz_text.as_str() == "def baz(): print('Version 2')";
 
-        let bar_baz_text = source_text(case.db(), baz.file());
+        let bar_baz_text = source_text(case.db(), baz_file);
         let did_update_bar_baz = bar_baz_text.as_str() == "def baz(): print('Version 2')";
 
         assert!(
@@ -1650,7 +1646,7 @@ mod unix {
             "def baz(): ..."
         );
         assert_eq!(
-            baz.file().path(case.db()).as_system_path(),
+            baz.file().unwrap().path(case.db()).as_system_path(),
             Some(&*baz_original)
         );
 
diff --git a/crates/ty_ide/src/lib.rs b/crates/ty_ide/src/lib.rs
index 27eb0fbbc6d1e..faa2941947033 100644
--- a/crates/ty_ide/src/lib.rs
+++ b/crates/ty_ide/src/lib.rs
@@ -188,7 +188,10 @@ impl HasNavigationTargets for Type<'_> {
 
 impl HasNavigationTargets for TypeDefinition<'_> {
     fn navigation_targets(&self, db: &dyn Db) -> NavigationTargets {
-        let full_range = self.full_range(db.upcast());
+        let Some(full_range) = self.full_range(db.upcast()) else {
+            return NavigationTargets::empty();
+        };
+
         NavigationTargets::single(NavigationTarget {
             file: full_range.file(),
             focus_range: self.focus_range(db.upcast()).unwrap_or(full_range).range(),
diff --git a/crates/ty_python_semantic/resources/mdtest/import/namespace.md b/crates/ty_python_semantic/resources/mdtest/import/namespace.md
index 91dff55c58cef..3b5f63e9818b3 100644
--- a/crates/ty_python_semantic/resources/mdtest/import/namespace.md
+++ b/crates/ty_python_semantic/resources/mdtest/import/namespace.md
@@ -29,8 +29,10 @@ import parent.child.two
 `from.py`
 
 ```py
-# TODO: This should not be an error
-from parent.child import one, two  # error: [unresolved-import]
+from parent.child import one, two
+
+reveal_type(one)  # revealed: <module 'parent.child.one'>
+reveal_type(two)  # revealed: <module 'parent.child.two'>
 ```
 
 ## Regular package in namespace package
@@ -105,3 +107,42 @@ reveal_type(x)  # revealed: Unknown | Literal["module"]
 
 import foo.bar  # error: [unresolved-import]
 ```
+
+## `from` import with namespace package
+
+Regression test for <https://github.com/astral-sh/ty/issues/363>
+
+`google/cloud/pubsub_v1/__init__.py`:
+
+```py
+class PublisherClient: ...
+```
+
+```py
+from google.cloud import pubsub_v1
+
+reveal_type(pubsub_v1.PublisherClient)  # revealed: <class 'PublisherClient'>
+```
+
+## `from` root importing sub-packages
+
+Regresssion test for <https://github.com/astral-sh/ty/issues/375>
+
+`opentelemetry/trace/__init__.py`:
+
+```py
+class Trace: ...
+```
+
+`opentelemetry/metrics/__init__.py`:
+
+```py
+class Metric: ...
+```
+
+```py
+from opentelemetry import trace, metrics
+
+reveal_type(trace)  # revealed: <module 'opentelemetry.trace'>
+reveal_type(metrics)  # revealed: <module 'opentelemetry.metrics'>
+```
diff --git a/crates/ty_python_semantic/src/dunder_all.rs b/crates/ty_python_semantic/src/dunder_all.rs
index 00a1628b78a17..4265de2ac6d8f 100644
--- a/crates/ty_python_semantic/src/dunder_all.rs
+++ b/crates/ty_python_semantic/src/dunder_all.rs
@@ -109,8 +109,10 @@ impl<'db> DunderAllNamesCollector<'db> {
                 else {
                     return false;
                 };
-                let Some(module_dunder_all_names) =
-                    dunder_all_names(self.db, module_literal.module(self.db).file())
+                let Some(module_dunder_all_names) = module_literal
+                    .module(self.db)
+                    .file()
+                    .and_then(|file| dunder_all_names(self.db, file))
                 else {
                     // The module either does not have a `__all__` variable or it is invalid.
                     return false;
@@ -179,7 +181,7 @@ impl<'db> DunderAllNamesCollector<'db> {
         let module_name =
             ModuleName::from_import_statement(self.db, self.file, import_from).ok()?;
         let module = resolve_module(self.db, &module_name)?;
-        dunder_all_names(self.db, module.file())
+        dunder_all_names(self.db, module.file()?)
     }
 
     /// Infer the type of a standalone expression.
diff --git a/crates/ty_python_semantic/src/module_resolver/module.rs b/crates/ty_python_semantic/src/module_resolver/module.rs
index c56d16dbdcab8..8ffd47762255e 100644
--- a/crates/ty_python_semantic/src/module_resolver/module.rs
+++ b/crates/ty_python_semantic/src/module_resolver/module.rs
@@ -14,15 +14,16 @@ pub struct Module {
 }
 
 impl Module {
-    pub(crate) fn new(
+    pub(crate) fn file_module(
         name: ModuleName,
         kind: ModuleKind,
         search_path: SearchPath,
         file: File,
     ) -> Self {
         let known = KnownModule::try_from_search_path_and_name(&search_path, &name);
+
         Self {
-            inner: Arc::new(ModuleInner {
+            inner: Arc::new(ModuleInner::FileModule {
                 name,
                 kind,
                 search_path,
@@ -32,19 +33,36 @@ impl Module {
         }
     }
 
+    pub(crate) fn namespace_package(name: ModuleName) -> Self {
+        Self {
+            inner: Arc::new(ModuleInner::NamespacePackage { name }),
+        }
+    }
+
     /// The absolute name of the module (e.g. `foo.bar`)
     pub fn name(&self) -> &ModuleName {
-        &self.inner.name
+        match &*self.inner {
+            ModuleInner::FileModule { name, .. } => name,
+            ModuleInner::NamespacePackage { name, .. } => name,
+        }
     }
 
     /// The file to the source code that defines this module
-    pub fn file(&self) -> File {
-        self.inner.file
+    ///
+    /// This is `None` for namespace packages.
+    pub fn file(&self) -> Option<File> {
+        match &*self.inner {
+            ModuleInner::FileModule { file, .. } => Some(*file),
+            ModuleInner::NamespacePackage { .. } => None,
+        }
     }
 
     /// Is this a module that we special-case somehow? If so, which one?
     pub fn known(&self) -> Option<KnownModule> {
-        self.inner.known
+        match &*self.inner {
+            ModuleInner::FileModule { known, .. } => *known,
+            ModuleInner::NamespacePackage { .. } => None,
+        }
     }
 
     /// Does this module represent the given known module?
@@ -53,13 +71,19 @@ impl Module {
     }
 
     /// The search path from which the module was resolved.
-    pub(crate) fn search_path(&self) -> &SearchPath {
-        &self.inner.search_path
+    pub(crate) fn search_path(&self) -> Option<&SearchPath> {
+        match &*self.inner {
+            ModuleInner::FileModule { search_path, .. } => Some(search_path),
+            ModuleInner::NamespacePackage { .. } => None,
+        }
     }
 
     /// Determine whether this module is a single-file module or a package
     pub fn kind(&self) -> ModuleKind {
-        self.inner.kind
+        match &*self.inner {
+            ModuleInner::FileModule { kind, .. } => *kind,
+            ModuleInner::NamespacePackage { .. } => ModuleKind::Package,
+        }
     }
 }
 
@@ -70,17 +94,26 @@ impl std::fmt::Debug for Module {
             .field("kind", &self.kind())
             .field("file", &self.file())
             .field("search_path", &self.search_path())
+            .field("known", &self.known())
             .finish()
     }
 }
 
 #[derive(PartialEq, Eq, Hash)]
-struct ModuleInner {
-    name: ModuleName,
-    kind: ModuleKind,
-    search_path: SearchPath,
-    file: File,
-    known: Option<KnownModule>,
+enum ModuleInner {
+    /// A module that resolves to a file (`lib.py` or `package/__init__.py`)
+    FileModule {
+        name: ModuleName,
+        kind: ModuleKind,
+        search_path: SearchPath,
+        file: File,
+        known: Option<KnownModule>,
+    },
+
+    /// A namespace package. Namespace packages are special because
+    /// there are multiple possible paths and they have no corresponding
+    /// code file.
+    NamespacePackage { name: ModuleName },
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
diff --git a/crates/ty_python_semantic/src/module_resolver/path.rs b/crates/ty_python_semantic/src/module_resolver/path.rs
index 7e923eeae52f0..7410e7a748bcd 100644
--- a/crates/ty_python_semantic/src/module_resolver/path.rs
+++ b/crates/ty_python_semantic/src/module_resolver/path.rs
@@ -143,6 +143,23 @@ impl ModulePath {
         }
     }
 
+    pub(super) fn to_system_path(&self) -> Option<SystemPathBuf> {
+        let ModulePath {
+            search_path,
+            relative_path,
+        } = self;
+        match &*search_path.0 {
+            SearchPathInner::Extra(search_path)
+            | SearchPathInner::FirstParty(search_path)
+            | SearchPathInner::SitePackages(search_path)
+            | SearchPathInner::Editable(search_path) => Some(search_path.join(relative_path)),
+            SearchPathInner::StandardLibraryCustom(stdlib_root) => {
+                Some(stdlib_root.join(relative_path))
+            }
+            SearchPathInner::StandardLibraryVendored(_) => None,
+        }
+    }
+
     #[must_use]
     pub(super) fn to_file(&self, resolver: &ResolverContext) -> Option<File> {
         let db = resolver.db.upcast();
diff --git a/crates/ty_python_semantic/src/module_resolver/resolver.rs b/crates/ty_python_semantic/src/module_resolver/resolver.rs
index 5f4aa1e1970d0..d39edc57caa1e 100644
--- a/crates/ty_python_semantic/src/module_resolver/resolver.rs
+++ b/crates/ty_python_semantic/src/module_resolver/resolver.rs
@@ -39,22 +39,24 @@ pub(crate) fn resolve_module_query<'db>(
     let name = module_name.name(db);
     let _span = tracing::trace_span!("resolve_module", %name).entered();
 
-    let Some((search_path, resolved_module)) = resolve_name(db, name) else {
+    let Some(resolved) = resolve_name(db, name) else {
         tracing::debug!("Module `{name}` not found in search paths");
         return None;
     };
 
-    tracing::trace!(
-        "Resolved module `{name}` to `{path}`",
-        path = resolved_module.file.path(db)
-    );
-
-    let module = Module::new(
-        name.clone(),
-        resolved_module.kind,
-        search_path,
-        resolved_module.file,
-    );
+    let module = match resolved {
+        ResolvedName::FileModule(module) => {
+            tracing::trace!(
+                "Resolved module `{name}` to `{path}`",
+                path = module.file.path(db)
+            );
+            Module::file_module(name.clone(), module.kind, module.search_path, module.file)
+        }
+        ResolvedName::NamespacePackage => {
+            tracing::trace!("Module `{name}` is a namespace package");
+            Module::namespace_package(name.clone())
+        }
+    };
 
     Some(module)
 }
@@ -117,8 +119,9 @@ pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option<Module> {
     // root paths, but that the module corresponding to `path` is in a lower priority search path,
     // in which case we ignore it.
     let module = resolve_module(db, &module_name)?;
+    let module_file = module.file()?;
 
-    if file.path(db) == module.file().path(db) {
+    if file.path(db) == module_file.path(db) {
         Some(module)
     } else {
         // This path is for a module with the same name but with a different precedence. For example:
@@ -616,7 +619,7 @@ struct ModuleNameIngredient<'db> {
 
 /// Given a module name and a list of search paths in which to lookup modules,
 /// attempt to resolve the module name
-fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(SearchPath, ResolvedModule)> {
+fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<ResolvedName> {
     let program = Program::get(db);
     let python_version = program.python_version(db);
     let resolver_state = ResolverContext::new(db, python_version);
@@ -625,6 +628,7 @@ fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(SearchPath, ResolvedM
 
     let name = RelaxedModuleName::new(name);
     let stub_name = name.to_stub_package();
+    let mut is_namespace_package = false;
 
     for search_path in search_paths(db) {
         // When a builtin module is imported, standard module resolution is bypassed:
@@ -636,16 +640,19 @@ fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(SearchPath, ResolvedM
         }
 
         if !search_path.is_standard_library() {
-            match resolve_module_in_search_path(&resolver_state, &stub_name, search_path) {
-                Ok(resolved_module) => {
-                    if resolved_module.package_kind.is_root() && resolved_module.kind.is_module() {
+            match resolve_name_in_search_path(&resolver_state, &stub_name, search_path) {
+                Ok((package_kind, ResolvedName::FileModule(module))) => {
+                    if package_kind.is_root() && module.kind.is_module() {
                         tracing::trace!(
                             "Search path '{search_path} contains a module named `{stub_name}` but a standalone module isn't a valid stub."
                         );
                     } else {
-                        return Some((search_path.clone(), resolved_module));
+                        return Some(ResolvedName::FileModule(module));
                     }
                 }
+                Ok((_, ResolvedName::NamespacePackage)) => {
+                    is_namespace_package = true;
+                }
                 Err(PackageKind::Root) => {
                     tracing::trace!(
                         "Search path '{search_path}' contains no stub package named `{stub_name}`."
@@ -670,8 +677,13 @@ fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(SearchPath, ResolvedM
             }
         }
 
-        match resolve_module_in_search_path(&resolver_state, &name, search_path) {
-            Ok(resolved_module) => return Some((search_path.clone(), resolved_module)),
+        match resolve_name_in_search_path(&resolver_state, &name, search_path) {
+            Ok((_, ResolvedName::FileModule(module))) => {
+                return Some(ResolvedName::FileModule(module));
+            }
+            Ok((_, ResolvedName::NamespacePackage)) => {
+                is_namespace_package = true;
+            }
             Err(kind) => match kind {
                 PackageKind::Root => {
                     tracing::trace!(
@@ -693,21 +705,36 @@ fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(SearchPath, ResolvedM
         }
     }
 
+    if is_namespace_package {
+        return Some(ResolvedName::NamespacePackage);
+    }
+
     None
 }
 
 #[derive(Debug)]
-struct ResolvedModule {
+enum ResolvedName {
+    /// A module that resolves to a file.
+    FileModule(ResolvedFileModule),
+
+    /// The module name resolved to a namespace package.
+    ///
+    /// For example, `from opentelemetry import trace, metrics` where `opentelemetry` is a namespace package (and `trace` and `metrics` are sub packages).
+    NamespacePackage,
+}
+
+#[derive(Debug)]
+struct ResolvedFileModule {
     kind: ModuleKind,
-    package_kind: PackageKind,
+    search_path: SearchPath,
     file: File,
 }
 
-fn resolve_module_in_search_path(
+fn resolve_name_in_search_path(
     context: &ResolverContext,
     name: &RelaxedModuleName,
     search_path: &SearchPath,
-) -> Result<ResolvedModule, PackageKind> {
+) -> Result<(PackageKind, ResolvedName), PackageKind> {
     let mut components = name.components();
     let module_name = components.next_back().unwrap();
 
@@ -720,22 +747,55 @@ fn resolve_module_in_search_path(
     // Check for a regular package first (highest priority)
     package_path.push("__init__");
     if let Some(regular_package) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: regular_package,
-            kind: ModuleKind::Package,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                search_path: search_path.clone(),
+                kind: ModuleKind::Package,
+                file: regular_package,
+            }),
+        ));
     }
 
     // Check for a file module next
     package_path.pop();
 
     if let Some(file_module) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: file_module,
-            kind: ModuleKind::Module,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                file: file_module,
+                kind: ModuleKind::Module,
+                search_path: search_path.clone(),
+            }),
+        ));
+    }
+
+    // Last resort, check if a folder with the given name exists.
+    // If so, then this is a namespace package.
+    // We need to skip this check for typeshed because the `resolve_file_module` can also return `None`
+    // if the `__init__.py` exists but isn't available for the current Python version.
+    // Let's assume that the `xml` module is only available on Python 3.11+ and we're resolving for Python 3.10:
+    // * `resolve_file_module("xml/__init__.pyi")` returns `None` even though the file exists but the
+    //   module isn't available for the current Python version.
+    // * The check here would now return `true` because the `xml` directory exists, resulting
+    //   in a false positive for a namespace package.
+    //
+    // Since typeshed doesn't use any namespace packages today (May 2025), simply skip this
+    // check which also helps performance. If typeshed ever uses namespace packages, ensure that
+    // this check also takes the `VERSIONS` file into consideration.
+    if !search_path.is_standard_library() && package_path.is_directory(context) {
+        if let Some(path) = package_path.to_system_path() {
+            let system = context.db.system();
+            if system.case_sensitivity().is_case_sensitive()
+                || system.path_exists_case_sensitive(
+                    &path,
+                    package_path.search_path().as_system_path().unwrap(),
+                )
+            {
+                return Ok((resolved_package.kind, ResolvedName::NamespacePackage));
+            }
+        }
     }
 
     Err(resolved_package.kind)
@@ -937,11 +997,11 @@ mod tests {
         );
 
         assert_eq!("foo", foo_module.name());
-        assert_eq!(&src, foo_module.search_path());
+        assert_eq!(&src, foo_module.search_path().unwrap());
         assert_eq!(ModuleKind::Module, foo_module.kind());
 
         let expected_foo_path = src.join("foo.py");
-        assert_eq!(&expected_foo_path, foo_module.file().path(&db));
+        assert_eq!(&expected_foo_path, foo_module.file().unwrap().path(&db));
         assert_eq!(
             Some(foo_module),
             path_to_module(&db, &FilePath::System(expected_foo_path))
@@ -958,7 +1018,10 @@ mod tests {
         let builtins_module_name = ModuleName::new_static("builtins").unwrap();
         let builtins = resolve_module(&db, &builtins_module_name).expect("builtins to resolve");
 
-        assert_eq!(builtins.file().path(&db), &stdlib.join("builtins.pyi"));
+        assert_eq!(
+            builtins.file().unwrap().path(&db),
+            &stdlib.join("builtins.pyi")
+        );
     }
 
     #[test]
@@ -979,7 +1042,10 @@ mod tests {
         let builtins_module_name = ModuleName::new_static("builtins").unwrap();
         let builtins = resolve_module(&db, &builtins_module_name).expect("builtins to resolve");
 
-        assert_eq!(builtins.file().path(&db), &stdlib.join("builtins.pyi"));
+        assert_eq!(
+            builtins.file().unwrap().path(&db),
+            &stdlib.join("builtins.pyi")
+        );
     }
 
     #[test]
@@ -1002,11 +1068,14 @@ mod tests {
             resolve_module(&db, &functools_module_name).as_ref()
         );
 
-        assert_eq!(&stdlib, functools_module.search_path());
+        assert_eq!(&stdlib, functools_module.search_path().unwrap());
         assert_eq!(ModuleKind::Module, functools_module.kind());
 
         let expected_functools_path = stdlib.join("functools.pyi");
-        assert_eq!(&expected_functools_path, functools_module.file().path(&db));
+        assert_eq!(
+            &expected_functools_path,
+            functools_module.file().unwrap().path(&db)
+        );
 
         assert_eq!(
             Some(functools_module),
@@ -1052,7 +1121,7 @@ mod tests {
             let resolved_module = resolve_module(&db, &module_name).unwrap_or_else(|| {
                 panic!("Expected module {module_name} to exist in the mock stdlib")
             });
-            let search_path = resolved_module.search_path();
+            let search_path = resolved_module.search_path().unwrap();
             assert_eq!(
                 &stdlib, search_path,
                 "Search path for {module_name} was unexpectedly {search_path:?}"
@@ -1148,7 +1217,7 @@ mod tests {
             let resolved_module = resolve_module(&db, &module_name).unwrap_or_else(|| {
                 panic!("Expected module {module_name} to exist in the mock stdlib")
             });
-            let search_path = resolved_module.search_path();
+            let search_path = resolved_module.search_path().unwrap();
             assert_eq!(
                 &stdlib, search_path,
                 "Search path for {module_name} was unexpectedly {search_path:?}"
@@ -1209,9 +1278,12 @@ mod tests {
             Some(&functools_module),
             resolve_module(&db, &functools_module_name).as_ref()
         );
-        assert_eq!(&src, functools_module.search_path());
+        assert_eq!(&src, functools_module.search_path().unwrap());
         assert_eq!(ModuleKind::Module, functools_module.kind());
-        assert_eq!(&src.join("functools.py"), functools_module.file().path(&db));
+        assert_eq!(
+            &src.join("functools.py"),
+            functools_module.file().unwrap().path(&db)
+        );
 
         assert_eq!(
             Some(functools_module),
@@ -1230,9 +1302,9 @@ mod tests {
         let pydoc_data_topics = resolve_module(&db, &pydoc_data_topics_name).unwrap();
 
         assert_eq!("pydoc_data.topics", pydoc_data_topics.name());
-        assert_eq!(pydoc_data_topics.search_path(), &stdlib);
+        assert_eq!(pydoc_data_topics.search_path().unwrap(), &stdlib);
         assert_eq!(
-            pydoc_data_topics.file().path(&db),
+            pydoc_data_topics.file().unwrap().path(&db),
             &stdlib.join("pydoc_data/topics.pyi")
         );
     }
@@ -1247,8 +1319,8 @@ mod tests {
         let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
 
         assert_eq!("foo", foo_module.name());
-        assert_eq!(&src, foo_module.search_path());
-        assert_eq!(&foo_path, foo_module.file().path(&db));
+        assert_eq!(&src, foo_module.search_path().unwrap());
+        assert_eq!(&foo_path, foo_module.file().unwrap().path(&db));
 
         assert_eq!(
             Some(&foo_module),
@@ -1274,8 +1346,8 @@ mod tests {
         let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
         let foo_init_path = src.join("foo/__init__.py");
 
-        assert_eq!(&src, foo_module.search_path());
-        assert_eq!(&foo_init_path, foo_module.file().path(&db));
+        assert_eq!(&src, foo_module.search_path().unwrap());
+        assert_eq!(&foo_init_path, foo_module.file().unwrap().path(&db));
         assert_eq!(ModuleKind::Package, foo_module.kind());
 
         assert_eq!(
@@ -1297,8 +1369,8 @@ mod tests {
         let foo = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
         let foo_stub = src.join("foo.pyi");
 
-        assert_eq!(&src, foo.search_path());
-        assert_eq!(&foo_stub, foo.file().path(&db));
+        assert_eq!(&src, foo.search_path().unwrap());
+        assert_eq!(&foo_stub, foo.file().unwrap().path(&db));
 
         assert_eq!(Some(foo), path_to_module(&db, &FilePath::System(foo_stub)));
         assert_eq!(
@@ -1321,8 +1393,8 @@ mod tests {
             resolve_module(&db, &ModuleName::new_static("foo.bar.baz").unwrap()).unwrap();
         let baz_path = src.join("foo/bar/baz.py");
 
-        assert_eq!(&src, baz_module.search_path());
-        assert_eq!(&baz_path, baz_module.file().path(&db));
+        assert_eq!(&src, baz_module.search_path().unwrap());
+        assert_eq!(&baz_path, baz_module.file().unwrap().path(&db));
 
         assert_eq!(
             Some(baz_module),
@@ -1345,8 +1417,8 @@ mod tests {
         let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
         let foo_src_path = src.join("foo.py");
 
-        assert_eq!(&src, foo_module.search_path());
-        assert_eq!(&foo_src_path, foo_module.file().path(&db));
+        assert_eq!(&src, foo_module.search_path().unwrap());
+        assert_eq!(&foo_src_path, foo_module.file().unwrap().path(&db));
         assert_eq!(
             Some(foo_module),
             path_to_module(&db, &FilePath::System(foo_src_path))
@@ -1413,14 +1485,14 @@ mod tests {
 
         assert_ne!(foo_module, bar_module);
 
-        assert_eq!(&src, foo_module.search_path());
-        assert_eq!(&foo, foo_module.file().path(&db));
+        assert_eq!(&src, foo_module.search_path().unwrap());
+        assert_eq!(&foo, foo_module.file().unwrap().path(&db));
 
         // `foo` and `bar` shouldn't resolve to the same file
 
-        assert_eq!(&src, bar_module.search_path());
-        assert_eq!(&bar, bar_module.file().path(&db));
-        assert_eq!(&foo, foo_module.file().path(&db));
+        assert_eq!(&src, bar_module.search_path().unwrap());
+        assert_eq!(&bar, bar_module.file().unwrap().path(&db));
+        assert_eq!(&foo, foo_module.file().unwrap().path(&db));
 
         assert_ne!(&foo_module, &bar_module);
 
@@ -1484,7 +1556,7 @@ mod tests {
         let foo_file = system_path_to_file(&db, &foo_path).expect("foo.py to exist");
 
         let foo_module = resolve_module(&db, &foo_module_name).expect("Foo module to resolve");
-        assert_eq!(foo_file, foo_module.file());
+        assert_eq!(foo_file, foo_module.file().unwrap());
 
         Ok(())
     }
@@ -1500,7 +1572,7 @@ mod tests {
         let foo_module = resolve_module(&db, &foo_module_name).expect("foo module to exist");
         let foo_init_path = src.join("foo/__init__.py");
 
-        assert_eq!(&foo_init_path, foo_module.file().path(&db));
+        assert_eq!(&foo_init_path, foo_module.file().unwrap().path(&db));
 
         // Delete `foo/__init__.py` and the `foo` folder. `foo` should now resolve to `foo.py`
         db.memory_file_system().remove_file(&foo_init_path)?;
@@ -1510,7 +1582,7 @@ mod tests {
         File::sync_path(&mut db, foo_init_path.parent().unwrap());
 
         let foo_module = resolve_module(&db, &foo_module_name).expect("Foo module to resolve");
-        assert_eq!(&src.join("foo.py"), foo_module.file().path(&db));
+        assert_eq!(&src.join("foo.py"), foo_module.file().unwrap().path(&db));
 
         Ok(())
     }
@@ -1536,9 +1608,9 @@ mod tests {
         let stdlib_functools_path = stdlib.join("functools.pyi");
 
         let functools_module = resolve_module(&db, &functools_module_name).unwrap();
-        assert_eq!(functools_module.search_path(), &stdlib);
+        assert_eq!(functools_module.search_path().unwrap(), &stdlib);
         assert_eq!(
-            Ok(functools_module.file()),
+            Ok(functools_module.file().unwrap()),
             system_path_to_file(&db, &stdlib_functools_path)
         );
 
@@ -1556,9 +1628,9 @@ mod tests {
             ModuleNameIngredient::new(&db, functools_module_name),
             &events,
         );
-        assert_eq!(functools_module.search_path(), &stdlib);
+        assert_eq!(functools_module.search_path().unwrap(), &stdlib);
         assert_eq!(
-            Ok(functools_module.file()),
+            Ok(functools_module.file().unwrap()),
             system_path_to_file(&db, &stdlib_functools_path)
         );
     }
@@ -1582,9 +1654,9 @@ mod tests {
 
         let functools_module_name = ModuleName::new_static("functools").unwrap();
         let functools_module = resolve_module(&db, &functools_module_name).unwrap();
-        assert_eq!(functools_module.search_path(), &stdlib);
+        assert_eq!(functools_module.search_path().unwrap(), &stdlib);
         assert_eq!(
-            Ok(functools_module.file()),
+            Ok(functools_module.file().unwrap()),
             system_path_to_file(&db, stdlib.join("functools.pyi"))
         );
 
@@ -1593,9 +1665,9 @@ mod tests {
         let src_functools_path = src.join("functools.py");
         db.write_file(&src_functools_path, "FOO: int").unwrap();
         let functools_module = resolve_module(&db, &functools_module_name).unwrap();
-        assert_eq!(functools_module.search_path(), &src);
+        assert_eq!(functools_module.search_path().unwrap(), &src);
         assert_eq!(
-            Ok(functools_module.file()),
+            Ok(functools_module.file().unwrap()),
             system_path_to_file(&db, &src_functools_path)
         );
     }
@@ -1624,9 +1696,9 @@ mod tests {
         let src_functools_path = src.join("functools.py");
 
         let functools_module = resolve_module(&db, &functools_module_name).unwrap();
-        assert_eq!(functools_module.search_path(), &src);
+        assert_eq!(functools_module.search_path().unwrap(), &src);
         assert_eq!(
-            Ok(functools_module.file()),
+            Ok(functools_module.file().unwrap()),
             system_path_to_file(&db, &src_functools_path)
         );
 
@@ -1637,9 +1709,9 @@ mod tests {
             .unwrap();
         File::sync_path(&mut db, &src_functools_path);
         let functools_module = resolve_module(&db, &functools_module_name).unwrap();
-        assert_eq!(functools_module.search_path(), &stdlib);
+        assert_eq!(functools_module.search_path().unwrap(), &stdlib);
         assert_eq!(
-            Ok(functools_module.file()),
+            Ok(functools_module.file().unwrap()),
             system_path_to_file(&db, stdlib.join("functools.pyi"))
         );
     }
@@ -1662,11 +1734,11 @@ mod tests {
         let foo_bar_module = resolve_module(&db, &foo_bar_module_name).unwrap();
 
         assert_eq!(
-            foo_module.file().path(&db),
+            foo_module.file().unwrap().path(&db),
             &FilePath::system("/x/src/foo/__init__.py")
         );
         assert_eq!(
-            foo_bar_module.file().path(&db),
+            foo_bar_module.file().unwrap().path(&db),
             &FilePath::system("/x/src/foo/bar.py")
         );
     }
@@ -1693,7 +1765,7 @@ mod tests {
         let bar_module_name = ModuleName::new_static("bar").unwrap();
         let bar_module = resolve_module(&db, &bar_module_name).unwrap();
         assert_eq!(
-            bar_module.file().path(&db),
+            bar_module.file().unwrap().path(&db),
             &FilePath::system("/y/src/bar.py")
         );
     }
@@ -1713,7 +1785,7 @@ mod tests {
         let foo_module = resolve_module(&db, &foo_module_name).unwrap();
 
         assert_eq!(
-            foo_module.file().path(&db),
+            foo_module.file().unwrap().path(&db),
             &FilePath::system("/x/y/src/foo.pyi")
         );
     }
@@ -1764,13 +1836,19 @@ not_a_directory
         let spam_module = resolve_module(&db, &spam_module_name).unwrap();
 
         assert_eq!(
-            foo_module.file().path(&db),
+            foo_module.file().unwrap().path(&db),
             &FilePath::system("/x/y/src/foo.pyi")
         );
-        assert_eq!(a_module.file().path(&db), &FilePath::system("/a.py"));
-        assert_eq!(b_module.file().path(&db), &FilePath::system("/baz/b.py"));
         assert_eq!(
-            spam_module.file().path(&db),
+            a_module.file().unwrap().path(&db),
+            &FilePath::system("/a.py")
+        );
+        assert_eq!(
+            b_module.file().unwrap().path(&db),
+            &FilePath::system("/baz/b.py")
+        );
+        assert_eq!(
+            spam_module.file().unwrap().path(&db),
             &FilePath::System(site_packages.join("spam/spam.py"))
         );
     }
@@ -1791,14 +1869,14 @@ not_a_directory
 
         let foo_module = resolve_module(&db, &foo_module_name).unwrap();
         assert_eq!(
-            foo_module.file().path(&db),
+            foo_module.file().unwrap().path(&db),
             &FilePath::system("/x/src/foo.py")
         );
 
         db.clear_salsa_events();
         let bar_module = resolve_module(&db, &bar_module_name).unwrap();
         assert_eq!(
-            bar_module.file().path(&db),
+            bar_module.file().unwrap().path(&db),
             &FilePath::system("/y/src/bar.py")
         );
         let events = db.take_salsa_events();
@@ -1823,7 +1901,7 @@ not_a_directory
         let foo_module_name = ModuleName::new_static("foo").unwrap();
         let foo_module = resolve_module(&db, &foo_module_name).unwrap();
         assert_eq!(
-            foo_module.file().path(&db),
+            foo_module.file().unwrap().path(&db),
             &FilePath::system("/x/src/foo.py")
         );
 
@@ -1851,7 +1929,7 @@ not_a_directory
         let foo_module = resolve_module(&db, &foo_module_name).unwrap();
         let src_path = SystemPathBuf::from("/x/src");
         assert_eq!(
-            foo_module.file().path(&db),
+            foo_module.file().unwrap().path(&db),
             &FilePath::System(src_path.join("foo.py"))
         );
 
@@ -1925,7 +2003,10 @@ not_a_directory
         // take precedence over the second `site-packages` directory...
         let a_module_name = ModuleName::new_static("a").unwrap();
         let a_module = resolve_module(&db, &a_module_name).unwrap();
-        assert_eq!(a_module.file().path(&db), &editable_install_location);
+        assert_eq!(
+            a_module.file().unwrap().path(&db),
+            &editable_install_location
+        );
 
         db.memory_file_system()
             .remove_file(&site_packages_pth)
@@ -1936,7 +2017,10 @@ not_a_directory
         // the editable install no longer exists, so the module now resolves to the file in the
         // second `site-packages` directory
         let a_module = resolve_module(&db, &a_module_name).unwrap();
-        assert_eq!(a_module.file().path(&db), &system_site_packages_location);
+        assert_eq!(
+            a_module.file().unwrap().path(&db),
+            &system_site_packages_location
+        );
     }
 
     #[test]
@@ -2001,6 +2085,7 @@ not_a_directory
         assert!(
             a_module
                 .file()
+                .unwrap()
                 .path(&db)
                 .as_str()
                 .ends_with("src/a/__init__.py"),
@@ -2035,6 +2120,6 @@ not_a_directory
 
         let foo_module_file = File::new(&db, FilePath::System(installed_foo_module));
         let module = file_to_module(&db, foo_module_file).unwrap();
-        assert_eq!(module.search_path(), &site_packages);
+        assert_eq!(module.search_path().unwrap(), &site_packages);
     }
 }
diff --git a/crates/ty_python_semantic/src/semantic_index/builder.rs b/crates/ty_python_semantic/src/semantic_index/builder.rs
index c9328c02aa4f9..514c1f1676083 100644
--- a/crates/ty_python_semantic/src/semantic_index/builder.rs
+++ b/crates/ty_python_semantic/src/semantic_index/builder.rs
@@ -1336,7 +1336,9 @@ where
                             continue;
                         };
 
-                        let referenced_module = module.file();
+                        let Some(referenced_module) = module.file() else {
+                            continue;
+                        };
 
                         // In order to understand the visibility of definitions created by a `*` import,
                         // we need to know the visibility of the global-scope definitions in the
diff --git a/crates/ty_python_semantic/src/semantic_index/re_exports.rs b/crates/ty_python_semantic/src/semantic_index/re_exports.rs
index 3c3c664bbd4ff..b8002dbf0bd2a 100644
--- a/crates/ty_python_semantic/src/semantic_index/re_exports.rs
+++ b/crates/ty_python_semantic/src/semantic_index/re_exports.rs
@@ -244,7 +244,12 @@ impl<'db> Visitor<'db> for ExportFinder<'db> {
                                     .ok()
                                     .and_then(|module_name| resolve_module(self.db, &module_name))
                                     .iter()
-                                    .flat_map(|module| exported_names(self.db, module.file()))
+                                    .flat_map(|module| {
+                                        module
+                                            .file()
+                                            .map(|file| exported_names(self.db, file))
+                                            .unwrap_or_default()
+                                    })
                             {
                                 self.possibly_add_export(export, PossibleExportKind::Normal);
                             }
diff --git a/crates/ty_python_semantic/src/symbol.rs b/crates/ty_python_semantic/src/symbol.rs
index f490bddcf32dc..8e20a08954fe9 100644
--- a/crates/ty_python_semantic/src/symbol.rs
+++ b/crates/ty_python_semantic/src/symbol.rs
@@ -342,19 +342,22 @@ pub(crate) fn imported_symbol<'db>(
 /// (e.g. `from builtins import int`).
 pub(crate) fn builtins_symbol<'db>(db: &'db dyn Db, symbol: &str) -> SymbolAndQualifiers<'db> {
     resolve_module(db, &KnownModule::Builtins.name())
-        .map(|module| {
-            symbol_impl(
-                db,
-                global_scope(db, module.file()),
-                symbol,
-                RequiresExplicitReExport::Yes,
+        .and_then(|module| {
+            let file = module.file()?;
+            Some(
+                symbol_impl(
+                    db,
+                    global_scope(db, file),
+                    symbol,
+                    RequiresExplicitReExport::Yes,
+                )
+                .or_fall_back_to(db, || {
+                    // We're looking up in the builtins namespace and not the module, so we should
+                    // do the normal lookup in `types.ModuleType` and not the special one as in
+                    // `imported_symbol`.
+                    module_type_implicit_global_symbol(db, symbol)
+                }),
             )
-            .or_fall_back_to(db, || {
-                // We're looking up in the builtins namespace and not the module, so we should
-                // do the normal lookup in `types.ModuleType` and not the special one as in
-                // `imported_symbol`.
-                module_type_implicit_global_symbol(db, symbol)
-            })
         })
         .unwrap_or_default()
 }
@@ -368,7 +371,10 @@ pub(crate) fn known_module_symbol<'db>(
     symbol: &str,
 ) -> SymbolAndQualifiers<'db> {
     resolve_module(db, &known_module.name())
-        .map(|module| imported_symbol(db, module.file(), symbol, None))
+        .and_then(|module| {
+            let file = module.file()?;
+            Some(imported_symbol(db, file, symbol, None))
+        })
         .unwrap_or_default()
 }
 
@@ -403,7 +409,8 @@ pub(crate) fn builtins_module_scope(db: &dyn Db) -> Option<ScopeId<'_>> {
 ///
 /// Can return `None` if a custom typeshed is used that is missing the core module in question.
 fn core_module_scope(db: &dyn Db, core_module: KnownModule) -> Option<ScopeId<'_>> {
-    resolve_module(db, &core_module.name()).map(|module| global_scope(db, module.file()))
+    let module = resolve_module(db, &core_module.name())?;
+    Some(global_scope(db, module.file()?))
 }
 
 /// Infer the combined type from an iterator of bindings, and return it
diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs
index efe9eaa9d0999..650d6dd01f619 100644
--- a/crates/ty_python_semantic/src/types.rs
+++ b/crates/ty_python_semantic/src/types.rs
@@ -7846,7 +7846,11 @@ impl<'db> ModuleLiteralType<'db> {
             }
         }
 
-        imported_symbol(db, self.module(db).file(), name, None).symbol
+        self.module(db)
+            .file()
+            .map(|file| imported_symbol(db, file, name, None))
+            .unwrap_or_default()
+            .symbol
     }
 }
 
diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs
index 9750bd530496b..a94022f9c31b9 100644
--- a/crates/ty_python_semantic/src/types/call/bind.rs
+++ b/crates/ty_python_semantic/src/types/call/bind.rs
@@ -611,8 +611,12 @@ impl<'db> Bindings<'db> {
                             if let [Some(ty)] = overload.parameter_types() {
                                 overload.set_return_type(match ty {
                                     Type::ModuleLiteral(module_literal) => {
-                                        match dunder_all_names(db, module_literal.module(db).file())
-                                        {
+                                        let all_names = module_literal
+                                            .module(db)
+                                            .file()
+                                            .map(|file| dunder_all_names(db, file))
+                                            .unwrap_or_default();
+                                        match all_names {
                                             Some(names) => {
                                                 let mut names = names.iter().collect::<Vec<_>>();
                                                 names.sort();
diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs
index 544c0e4437d76..c9034de603a5b 100644
--- a/crates/ty_python_semantic/src/types/class.rs
+++ b/crates/ty_python_semantic/src/types/class.rs
@@ -2888,7 +2888,7 @@ mod tests {
             let class_module = resolve_module(&db, &class.canonical_module(&db).name()).unwrap();
 
             assert_eq!(
-                KnownClass::try_from_file_and_name(&db, class_module.file(), class_name),
+                KnownClass::try_from_file_and_name(&db, class_module.file().unwrap(), class_name),
                 Some(class),
                 "`KnownClass::candidate_from_str` appears to be missing a case for `{class_name}`"
             );
diff --git a/crates/ty_python_semantic/src/types/definition.rs b/crates/ty_python_semantic/src/types/definition.rs
index 207aed39b685b..466673b09f3ea 100644
--- a/crates/ty_python_semantic/src/types/definition.rs
+++ b/crates/ty_python_semantic/src/types/definition.rs
@@ -24,16 +24,17 @@ impl TypeDefinition<'_> {
         }
     }
 
-    pub fn full_range(&self, db: &dyn Db) -> FileRange {
+    pub fn full_range(&self, db: &dyn Db) -> Option<FileRange> {
         match self {
             Self::Module(module) => {
-                let source = source_text(db.upcast(), module.file());
-                FileRange::new(module.file(), TextRange::up_to(source.text_len()))
+                let file = module.file()?;
+                let source = source_text(db.upcast(), file);
+                Some(FileRange::new(file, TextRange::up_to(source.text_len())))
             }
             Self::Class(definition)
             | Self::Function(definition)
             | Self::TypeVar(definition)
-            | Self::TypeAlias(definition) => definition.full_range(db),
+            | Self::TypeAlias(definition) => Some(definition.full_range(db)),
         }
     }
 }
diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs
index beb7fb260b108..1eac4a9d775ad 100644
--- a/crates/ty_python_semantic/src/types/infer.rs
+++ b/crates/ty_python_semantic/src/types/infer.rs
@@ -4049,7 +4049,7 @@ impl<'db> TypeInferenceBuilder<'db> {
         // (e.g. `from parent import submodule` inside the `parent` module).
         let import_is_self_referential = module_ty
             .into_module_literal()
-            .is_some_and(|module| self.file() == module.module(self.db()).file());
+            .is_some_and(|module| Some(self.file()) == module.module(self.db()).file());
 
         // First try loading the requested attribute from the module.
         if !import_is_self_referential {


Reviews:
user: login: MichaReiser
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T15:12:55Z
user: login: MichaReiser
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T11:54:08Z
user: login: sharkdp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T14:24:16Z
user: login: AlexWaygood
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T20:04:02Z
user: login: AlexWaygood
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T20:59:03Z
user: login: AlexWaygood
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T21:06:29Z
user: login: AlexWaygood
body: The primer hits look great!! I left some comments in `resolver.rs` -- not sure about some of the details there
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T21:07:09Z
user: login: MichaReiser
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-20T05:47:56Z
user: login: MichaReiser
body: Hmm, I just noticed that my comments are still pending
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-20T16:30:30Z
user: login: AlexWaygood
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-20T17:44:58Z
user: login: AlexWaygood
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-20T18:43:31Z
user: login: AlexWaygood
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-20T18:43:36Z

Review comments:
diff_hunk: @@ -79,7 +79,7 @@ impl Files {
     ///
     /// The operation always succeeds even if the path doesn't exist on disk, isn't accessible or if the path points to a directory.
     /// In these cases, a file with status [`FileStatus::NotFound`] is returned.
-    fn system(&self, db: &dyn Db, path: &SystemPath) -> File {
+    pub fn system(&self, db: &dyn Db, path: &SystemPath) -> File {
path: crates/ruff_db/src/files.rs
user: login: MichaReiser
body: Double check if this is needed
created_at: 2025-05-16T15:12:55Z
author_association: MEMBER
diff_hunk: @@ -69,7 +69,7 @@ jobs:
           echo "Project selector: $PRIMER_SELECTOR"
           # Allow the exit code to be 0 or 1, only fail for actual mypy_primer crashes/bugs
           uvx \
-            --from="git+https://github.com/hauntsaninja/mypy_primer@968b2b61c05f84462d6fcc78d2f5205bbb8b98c2" \
+            --from="git+https://github.com/hauntsaninja/mypy_primer@5b695a8d2b4382d36932abcb1a06e0d54df5586b" \
path: .github/workflows/mypy_primer.yaml
user: login: MichaReiser
body: For a more meaningful mypy primer result (pulls in https://github.com/hauntsaninja/mypy_primer/pull/171)

TODO: Revert before landing
created_at: 2025-05-19T11:54:08Z
author_association: MEMBER
diff_hunk: @@ -69,7 +69,7 @@ jobs:
           echo "Project selector: $PRIMER_SELECTOR"
           # Allow the exit code to be 0 or 1, only fail for actual mypy_primer crashes/bugs
           uvx \
-            --from="git+https://github.com/hauntsaninja/mypy_primer@968b2b61c05f84462d6fcc78d2f5205bbb8b98c2" \
+            --from="git+https://github.com/hauntsaninja/mypy_primer@5b695a8d2b4382d36932abcb1a06e0d54df5586b" \
path: .github/workflows/mypy_primer.yaml
user: login: sharkdp
body: [PR](https://github.com/hauntsaninja/mypy_primer/pull/171) has been merged:

```suggestion
            --from="git+https://github.com/hauntsaninja/mypy_primer@01a7ca325f674433c58e02416a867178d1571128" \
```
created_at: 2025-05-19T14:24:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -70,17 +94,26 @@ impl std::fmt::Debug for Module {
             .field("kind", &self.kind())
             .field("file", &self.file())
             .field("search_path", &self.search_path())
+            .field("known", &self.known())
             .finish()
     }
 }
 
 #[derive(PartialEq, Eq, Hash)]
-struct ModuleInner {
-    name: ModuleName,
-    kind: ModuleKind,
-    search_path: SearchPath,
-    file: File,
-    known: Option<KnownModule>,
+enum ModuleInner {
+    /// A module that resolves to a file (`lib.py` or `package/__init__.py`)
+    FileModule {
+        name: ModuleName,
+        kind: ModuleKind,
+        search_path: SearchPath,
+        file: File,
+        known: Option<KnownModule>,
path: crates/ty_python_semantic/src/module_resolver/module.rs
user: login: AlexWaygood
body: it's possible we might want namespace packages without `File`s to be recognized as `KnownModule`s in the future? But I can't think of a use case right now, so we can probably figure that out if and when it actually comes up.
created_at: 2025-05-19T20:04:02Z
author_association: MEMBER
diff_hunk: @@ -720,22 +747,46 @@ fn resolve_module_in_search_path(
     // Check for a regular package first (highest priority)
     package_path.push("__init__");
     if let Some(regular_package) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: regular_package,
-            kind: ModuleKind::Package,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                search_path: search_path.clone(),
+                kind: ModuleKind::Package,
+                file: regular_package,
+            }),
+        ));
     }
 
     // Check for a file module next
     package_path.pop();
 
     if let Some(file_module) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: file_module,
-            kind: ModuleKind::Module,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                file: file_module,
+                kind: ModuleKind::Module,
+                search_path: search_path.clone(),
+            }),
+        ));
+    }
+
+    // Last resort, check if a folder with the given name exists.
+    // If so, then this is a namespace package.
+    // Exclude the standard library because it has conditional modules and we don't
+    // want to mistake them as namespace packages.
+    if !search_path.is_standard_library() && package_path.is_directory(context) {
path: crates/ty_python_semantic/src/module_resolver/resolver.rs
user: login: AlexWaygood
body: Excluding the standard library implicitly here implicitly depends on the invariant that there will never be any namespace packages added to the standard library. But it does seem very unlikely that CPython would ever add any namespace packages to the stdlib, so this is probably okay. Though I'd prefer it if we made it explicit in this comment that we're relying on that invariant.

I'm also totally sure I understand why this exclusion is necessary, though. When you say "the standard library [...] has conditional modules", do you mean something like this?

https://github.com/astral-sh/ruff/blob/b302d89da3325c705f87a8343a16aad1723b67ab/crates/ty_vendored/vendor/typeshed/stdlib/VERSIONS#L293-L294

I'm not sure I understand why we'd ever accidentally infer a module in the stdlib as being a namespace package... when single-file modules are converted to become packages with submodules in later versions, typeshed generally pretends that they were always non-namespace packages and marks the submodule as newly added in the `VERSIONS` file
created_at: 2025-05-19T20:59:02Z
author_association: MEMBER
diff_hunk: @@ -720,22 +747,46 @@ fn resolve_module_in_search_path(
     // Check for a regular package first (highest priority)
     package_path.push("__init__");
     if let Some(regular_package) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: regular_package,
-            kind: ModuleKind::Package,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                search_path: search_path.clone(),
+                kind: ModuleKind::Package,
+                file: regular_package,
+            }),
+        ));
     }
 
     // Check for a file module next
     package_path.pop();
 
     if let Some(file_module) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: file_module,
-            kind: ModuleKind::Module,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                file: file_module,
+                kind: ModuleKind::Module,
+                search_path: search_path.clone(),
+            }),
+        ));
+    }
+
+    // Last resort, check if a folder with the given name exists.
+    // If so, then this is a namespace package.
+    // Exclude the standard library because it has conditional modules and we don't
+    // want to mistake them as namespace packages.
+    if !search_path.is_standard_library() && package_path.is_directory(context) {
+        if let Some(path) = package_path.to_system_path() {
+            let system = context.db.system();
+            if system.case_sensitivity().is_case_sensitive()
+                || system.path_exists_case_sensitive(
+                    &path,
+                    package_path.search_path().as_system_path().unwrap(),
+                )
+            {
+                return Ok((resolved_package.kind, ResolvedName::NamespacePackage));
+            }
path: crates/ty_python_semantic/src/module_resolver/resolver.rs
user: login: AlexWaygood
body: we return `Ok()` here if the system is case-sensitive _or_ the path exists according to a case-sensitive check...? That doesn't seem correct
created_at: 2025-05-19T21:06:29Z
author_association: MEMBER
diff_hunk: @@ -70,17 +94,26 @@ impl std::fmt::Debug for Module {
             .field("kind", &self.kind())
             .field("file", &self.file())
             .field("search_path", &self.search_path())
+            .field("known", &self.known())
             .finish()
     }
 }
 
 #[derive(PartialEq, Eq, Hash)]
-struct ModuleInner {
-    name: ModuleName,
-    kind: ModuleKind,
-    search_path: SearchPath,
-    file: File,
-    known: Option<KnownModule>,
+enum ModuleInner {
+    /// A module that resolves to a file (`lib.py` or `package/__init__.py`)
+    FileModule {
+        name: ModuleName,
+        kind: ModuleKind,
+        search_path: SearchPath,
+        file: File,
+        known: Option<KnownModule>,
path: crates/ty_python_semantic/src/module_resolver/module.rs
user: login: MichaReiser
body: That's possible if we want to special case some library. I haven't looked at `KnownModule` itself but I suspect that it won't be too hard to add but I don't see a need to do it today (and agree with you that we can do it in the future)
created_at: 2025-05-20T05:47:55Z
author_association: MEMBER
diff_hunk: @@ -720,22 +747,46 @@ fn resolve_module_in_search_path(
     // Check for a regular package first (highest priority)
     package_path.push("__init__");
     if let Some(regular_package) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: regular_package,
-            kind: ModuleKind::Package,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                search_path: search_path.clone(),
+                kind: ModuleKind::Package,
+                file: regular_package,
+            }),
+        ));
     }
 
     // Check for a file module next
     package_path.pop();
 
     if let Some(file_module) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: file_module,
-            kind: ModuleKind::Module,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                file: file_module,
+                kind: ModuleKind::Module,
+                search_path: search_path.clone(),
+            }),
+        ));
+    }
+
+    // Last resort, check if a folder with the given name exists.
+    // If so, then this is a namespace package.
+    // Exclude the standard library because it has conditional modules and we don't
+    // want to mistake them as namespace packages.
+    if !search_path.is_standard_library() && package_path.is_directory(context) {
path: crates/ty_python_semantic/src/module_resolver/resolver.rs
user: login: MichaReiser
body: > I'm also totally sure I understand why this exclusion is necessary, though. When you say "the standard library [...] has conditional modules", do you mean something like this?

Sort of, but for a package, the problem is that the `resolve_file_module` calls for `__init__` may fail but only because the module isn't available for this Python version. We would need to repeat the version check for namespace packages to avoid classifying the folder as a namespace package. There's actually a test that fails if we remove this check where we test that you can't import `xml` on an older python version (or newer?) and it started succeeding.


created_at: 2025-05-20T05:50:58Z
author_association: MEMBER
diff_hunk: @@ -720,22 +747,46 @@ fn resolve_module_in_search_path(
     // Check for a regular package first (highest priority)
     package_path.push("__init__");
     if let Some(regular_package) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: regular_package,
-            kind: ModuleKind::Package,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                search_path: search_path.clone(),
+                kind: ModuleKind::Package,
+                file: regular_package,
+            }),
+        ));
     }
 
     // Check for a file module next
     package_path.pop();
 
     if let Some(file_module) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: file_module,
-            kind: ModuleKind::Module,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                file: file_module,
+                kind: ModuleKind::Module,
+                search_path: search_path.clone(),
+            }),
+        ));
+    }
+
+    // Last resort, check if a folder with the given name exists.
+    // If so, then this is a namespace package.
+    // Exclude the standard library because it has conditional modules and we don't
+    // want to mistake them as namespace packages.
+    if !search_path.is_standard_library() && package_path.is_directory(context) {
+        if let Some(path) = package_path.to_system_path() {
+            let system = context.db.system();
+            if system.case_sensitivity().is_case_sensitive()
+                || system.path_exists_case_sensitive(
+                    &path,
+                    package_path.search_path().as_system_path().unwrap(),
+                )
+            {
+                return Ok((resolved_package.kind, ResolvedName::NamespacePackage));
+            }
path: crates/ty_python_semantic/src/module_resolver/resolver.rs
user: login: MichaReiser
body: Can you tell me why you think this isn't correct? 

The check here ensures that we don't return `true` if the module name and the name on disk use different casing:

* If the file system is case sensitive: The `is_directory` call would have failed if the casing doesn't match. That's why we can skip the extra check
* If the file system is case sensitive: Perform a case sensitive lookup and only return `Ok` if the path exists too.
created_at: 2025-05-20T05:52:42Z
author_association: MEMBER
diff_hunk: @@ -720,22 +747,46 @@ fn resolve_module_in_search_path(
     // Check for a regular package first (highest priority)
     package_path.push("__init__");
     if let Some(regular_package) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: regular_package,
-            kind: ModuleKind::Package,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                search_path: search_path.clone(),
+                kind: ModuleKind::Package,
+                file: regular_package,
+            }),
+        ));
     }
 
     // Check for a file module next
     package_path.pop();
 
     if let Some(file_module) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: file_module,
-            kind: ModuleKind::Module,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                file: file_module,
+                kind: ModuleKind::Module,
+                search_path: search_path.clone(),
+            }),
+        ));
+    }
+
+    // Last resort, check if a folder with the given name exists.
+    // If so, then this is a namespace package.
+    // Exclude the standard library because it has conditional modules and we don't
+    // want to mistake them as namespace packages.
+    if !search_path.is_standard_library() && package_path.is_directory(context) {
path: crates/ty_python_semantic/src/module_resolver/resolver.rs
user: login: AlexWaygood
body: I see, okay. It would be great if we could expand this comment a bit to make this clearer
created_at: 2025-05-20T17:44:58Z
author_association: MEMBER
diff_hunk: @@ -720,22 +747,46 @@ fn resolve_module_in_search_path(
     // Check for a regular package first (highest priority)
     package_path.push("__init__");
     if let Some(regular_package) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: regular_package,
-            kind: ModuleKind::Package,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                search_path: search_path.clone(),
+                kind: ModuleKind::Package,
+                file: regular_package,
+            }),
+        ));
     }
 
     // Check for a file module next
     package_path.pop();
 
     if let Some(file_module) = resolve_file_module(&package_path, context) {
-        return Ok(ResolvedModule {
-            file: file_module,
-            kind: ModuleKind::Module,
-            package_kind: resolved_package.kind,
-        });
+        return Ok((
+            resolved_package.kind,
+            ResolvedName::FileModule(ResolvedFileModule {
+                file: file_module,
+                kind: ModuleKind::Module,
+                search_path: search_path.clone(),
+            }),
+        ));
+    }
+
+    // Last resort, check if a folder with the given name exists.
+    // If so, then this is a namespace package.
+    // Exclude the standard library because it has conditional modules and we don't
+    // want to mistake them as namespace packages.
+    if !search_path.is_standard_library() && package_path.is_directory(context) {
+        if let Some(path) = package_path.to_system_path() {
+            let system = context.db.system();
+            if system.case_sensitivity().is_case_sensitive()
+                || system.path_exists_case_sensitive(
+                    &path,
+                    package_path.search_path().as_system_path().unwrap(),
+                )
+            {
+                return Ok((resolved_package.kind, ResolvedName::NamespacePackage));
+            }
path: crates/ty_python_semantic/src/module_resolver/resolver.rs
user: login: AlexWaygood
body: OK, I think I understand. Sorry for being dense!
created_at: 2025-05-20T18:43:30Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-16T15:16:12Z
body: <!-- generated-comment mypy_primer -->
## `mypy_primer` results
<details>
<summary>Changes were detected when running on open source projects</summary>

```diff
schema_salad (https://github.com/common-workflow-language/schema_salad)
+ error[unresolved-attribute] schema_salad/sourceline.py:12:25: Type `<module 'ruamel.yaml'>` has no attribute `comments`
+ error[unresolved-attribute] schema_salad/sourceline.py:13:22: Type `<module 'ruamel.yaml'>` has no attribute `comments`
+ error[unresolved-attribute] schema_salad/sourceline.py:30:24: Type `<module 'ruamel.yaml'>` has no attribute `comments`
+ error[unresolved-attribute] schema_salad/sourceline.py:271:38: Type `<module 'ruamel.yaml'>` has no attribute `comments`
- Found 247 diagnostics
+ Found 251 diagnostics

mitmproxy (https://github.com/mitmproxy/mitmproxy)
- error[unresolved-import] examples/contrib/test_jsondump.py:6:6: Cannot resolve imported module `mitmproxy.test`
+ error[unresolved-attribute] examples/contrib/test_jsondump.py:10:15: Type `<module 'mitmproxy.test.tutils'>` has no attribute `test_data`
- error[unresolved-import] examples/contrib/test_jsondump.py:7:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/test_jsondump.py:8:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/test_xss_scanner.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/test_xss_scanner.py:6:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/webscanner_helper/test_mapping.py:8:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/webscanner_helper/test_mapping.py:9:6: Cannot resolve imported module `mitmproxy.test`
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_mapping.py:66:9: Object of type `Literal[b"Test"]` is not assignable to attribute `content` on type `Response | None`
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_mapping.py:69:16: Attribute `content` on type `Response | None` is possibly unbound
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_mapping.py:78:9: Object of type `Literal[b"<body> Test </body>"]` is not assignable to attribute `content` on type `Response | None`
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_mapping.py:82:16: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_mapping.py:82:16: Attribute `decode` on type `bytes | None` is possibly unbound
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_mapping.py:91:9: Object of type `Literal[b"<body> Test </body>"]` is not assignable to attribute `content` on type `Response | None`
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_mapping.py:93:9: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_mapping.py:96:16: Attribute `content` on type `Response | None` is possibly unbound
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_mapping.py:105:9: Object of type `Literal[b"<title> Test </title>"]` is not assignable to attribute `content` on type `Response | None`
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_mapping.py:108:16: Attribute `content` on type `Response | None` is possibly unbound
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_mapping.py:143:9: Object of type `Literal[b"<title> Test </title>"]` is not assignable to attribute `content` on type `Response | None`
- error[unresolved-import] examples/contrib/webscanner_helper/test_proxyauth_selenium.py:11:6: Cannot resolve imported module `mitmproxy.test`
+ error[unresolved-attribute] examples/contrib/webscanner_helper/test_proxyauth_selenium.py:57:9: Unresolved attribute `is_replay` on type `Request`.
- error[unresolved-import] examples/contrib/webscanner_helper/test_proxyauth_selenium.py:12:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/webscanner_helper/test_urldict.py:2:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/webscanner_helper/test_urldict.py:3:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/webscanner_helper/test_urlindex.py:14:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/webscanner_helper/test_urlindex.py:15:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/webscanner_helper/test_urlinjection.py:11:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/webscanner_helper/test_urlinjection.py:12:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlindex.py:131:16: Attribute `status_code` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlindex.py:146:16: Attribute `status_code` on type `Response | None` is possibly unbound
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_urlindex.py:172:9: Object of type `Literal[404]` is not assignable to attribute `status_code` on type `Response | None`
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:39:41: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:41:37: Attribute `content` on type `Response | None` is possibly unbound
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_urlinjection.py:46:9: Object of type `Literal["<body></body>"]` is not assignable to attribute `text` on type `Response | None`
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:47:41: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:49:37: Attribute `content` on type `Response | None` is possibly unbound
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_urlinjection.py:54:9: Object of type `Literal[404]` is not assignable to attribute `status_code` on type `Response | None`
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:55:41: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:57:37: Attribute `content` on type `Response | None` is possibly unbound
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_urlinjection.py:72:9: Object of type `Literal[404]` is not assignable to attribute `status_code` on type `Response | None`
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:73:42: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:75:38: Attribute `content` on type `Response | None` is possibly unbound
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_urlinjection.py:90:9: Object of type `Literal[404]` is not assignable to attribute `status_code` on type `Response | None`
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:92:13: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:95:70: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:112:51: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] examples/contrib/webscanner_helper/test_urlinjection.py:114:47: Attribute `content` on type `Response | None` is possibly unbound
+ error[invalid-assignment] examples/contrib/webscanner_helper/test_watchdog.py:56:9: Object of type `Literal["Test Error"]` is not assignable to attribute `error` of type `Error | None`
- error[unresolved-import] examples/contrib/webscanner_helper/test_watchdog.py:10:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] examples/contrib/webscanner_helper/test_watchdog.py:11:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/examples/test_examples.py:63:20: Attribute `content` on type `Response | None` is possibly unbound
- error[unresolved-import] test/examples/test_examples.py:3:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/examples/test_examples.py:4:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/examples/test_examples.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/helper_tools/dumperview.py:7:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/helper_tools/dumperview.py:8:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/helper_tools/dumperview.py:54:5: Attribute `headers` on type `Response | None` is possibly unbound
+ error[invalid-assignment] test/helper_tools/dumperview.py:55:5: Object of type `bytes` is not assignable to attribute `content` on type `Response | None`
+ warning[possibly-unbound-attribute] test/helper_tools/dumperview.py:63:5: Attribute `headers` on type `Response | None` is possibly unbound
+ error[invalid-assignment] test/helper_tools/dumperview.py:64:5: Object of type `Literal[b"<html><body>Hello!</body></html>"]` is not assignable to attribute `content` on type `Response | None`
- error[unresolved-import] test/mitmproxy/addons/test_anticache.py:2:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_anticache.py:3:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_anticomp.py:2:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_anticomp.py:3:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_asgiapp.py:10:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_block.py:6:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_blocklist.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_blocklist.py:6:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_browser.py:4:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_blocklist.py:44:24: Attribute `status_code` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_blocklist.py:57:20: Attribute `status_code` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_blocklist.py:76:20: Attribute `msg` on type `Error | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_blocklist.py:76:35: Attribute `KILLED_MESSAGE` on type `Error | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_clientplayback.py:122:20: Attribute `status_code` on type `Response | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/addons/test_clientplayback.py:14:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_clientplayback.py:15:6: Cannot resolve imported module `mitmproxy.test`
+ error[invalid-assignment] test/mitmproxy/addons/test_clientplayback.py:182:5: Object of type `None` is not assignable to attribute `request` of type `Request`
- error[unresolved-import] test/mitmproxy/addons/test_command_history.py:6:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_comment.py:2:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_comment.py:3:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_core.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_core.py:6:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_core.py:92:16: Attribute `status_code` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_core.py:94:16: Attribute `status_code` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_core.py:95:16: Attribute `reason` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_core.py:99:16: Attribute `reason` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_core.py:101:16: Attribute `reason` on type `Response | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/addons/test_cut.py:10:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_cut.py:11:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_disable_h2c.py:39:20: Attribute `msg` on type `Error | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/addons/test_disable_h2c.py:3:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_disable_h2c.py:4:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_disable_h2c.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_dns_resolver.py:14:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_dns_resolver.py:15:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_dns_resolver.py:16:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dns_resolver.py:126:24: Attribute `response_code` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dns_resolver.py:128:24: Attribute `response_code` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dns_resolver.py:132:28: Attribute `response_code` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dns_resolver.py:134:28: Attribute `response_code` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dns_resolver.py:135:28: Attribute `answers` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dns_resolver.py:141:24: Attribute `answers` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dns_resolver.py:143:24: Attribute `answers` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dns_resolver.py:146:21: Attribute `answers` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dns_resolver.py:151:21: Attribute `answers` on type `DNSMessage | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/addons/test_dumper.py:13:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_dumper.py:14:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_dumper.py:15:6: Cannot resolve imported module `mitmproxy.test`
+ error[invalid-assignment] test/mitmproxy/addons/test_dumper.py:26:9: Object of type `Literal[b"foo"]` is not assignable to attribute `content` on type `Response | None`
+ error[invalid-assignment] test/mitmproxy/addons/test_dumper.py:77:9: Object of type `Literal[300]` is not assignable to attribute `status_code` on type `Response | None`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dumper.py:84:9: Attribute `headers` on type `Response | None` is possibly unbound
+ error[invalid-assignment] test/mitmproxy/addons/test_dumper.py:85:9: Object of type `Literal[400]` is not assignable to attribute `status_code` on type `Response | None`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dumper.py:101:5: Attribute `headers` on type `Response | None` is possibly unbound
+ error[invalid-assignment] test/mitmproxy/addons/test_dumper.py:102:5: Object of type `bytes` is not assignable to attribute `content` on type `Response | None`
+ error[invalid-argument-type] test/mitmproxy/addons/test_dumper.py:108:25: Argument to bound method `_echo_message` is incorrect: Expected `Message | TCPMessage | UDPMessage | WebSocketMessage`, found `Response | None`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dumper.py:115:5: Attribute `headers` on type `Response | None` is possibly unbound
+ error[invalid-assignment] test/mitmproxy/addons/test_dumper.py:116:5: Object of type `bytes` is not assignable to attribute `content` on type `Response | None`
+ error[invalid-argument-type] test/mitmproxy/addons/test_dumper.py:123:25: Argument to bound method `_echo_message` is incorrect: Expected `Message | TCPMessage | UDPMessage | WebSocketMessage`, found `Response | None`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dumper.py:143:9: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_dumper.py:144:9: Attribute `headers` on type `Response | None` is possibly unbound
+ error[invalid-assignment] test/mitmproxy/addons/test_dumper.py:145:9: Object of type `bytes` is not assignable to attribute `content` on type `Response | None`
+ error[invalid-assignment] test/mitmproxy/addons/test_dumper.py:146:9: Object of type `Headers` is not assignable to attribute `trailers` on type `Response | None`
+ error[invalid-assignment] test/mitmproxy/addons/test_dumper.py:289:9: Object of type `Literal[b"HTTP/2.0"]` is not assignable to attribute `http_version` on type `Response | None`
- error[unresolved-import] test/mitmproxy/addons/test_export.py:10:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_export.py:11:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_export.py:12:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_intercept.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_intercept.py:6:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_keepserving.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_maplocal.py:9:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_maplocal.py:10:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_maplocal.py:154:20: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_maplocal.py:162:20: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_maplocal.py:172:20: Attribute `content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_maplocal.py:183:20: Attribute `status_code` on type `Response | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/addons/test_mapremote.py:4:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_mapremote.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_modifybody.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_modifybody.py:6:6: Cannot resolve imported module `mitmproxy.test`
+ error[invalid-assignment] test/mitmproxy/addons/test_modifybody.py:41:13: Object of type `Literal[b"foo"]` is not assignable to attribute `content` on type `Response | None`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifybody.py:43:20: Attribute `content` on type `Response | None` is possibly unbound
+ error[invalid-assignment] test/mitmproxy/addons/test_modifybody.py:58:13: Object of type `Literal[b"foo"]` is not assignable to attribute `content` on type `Response | None`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifybody.py:62:21: Attribute `content` on type `Response | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/addons/test_modifyheaders.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_modifyheaders.py:6:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifyheaders.py:48:13: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifyheaders.py:50:20: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifyheaders.py:55:13: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifyheaders.py:57:20: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifyheaders.py:73:13: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifyheaders.py:75:33: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifyheaders.py:84:13: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifyheaders.py:86:33: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_modifyheaders.py:116:21: Attribute `headers` on type `Response | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/addons/test_next_layer.py:36:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_onboarding.py:4:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_proxyauth.py:11:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_proxyauth.py:12:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_proxyauth.py:107:20: Attribute `status_code` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_proxyauth.py:119:20: Attribute `status_code` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_proxyauth.py:223:20: Attribute `status_code` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_proxyauth.py:229:20: Attribute `status_code` on type `Response | None` is possibly unbound
+ error[invalid-assignment] test/mitmproxy/addons/test_proxyauth.py:243:13: Object of type `Literal[True]` is not assignable to attribute `is_replay` of type `str | None`
- error[unresolved-import] test/mitmproxy/addons/test_proxyserver.py:37:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_proxyserver.py:38:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_readfile.py:10:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_readfile.py:11:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_save.py:7:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_save.py:8:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_savehar.py:251:13: Attribute `content` on type `Response | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/addons/test_savehar.py:17:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_savehar.py:18:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_savehar.py:19:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_script.py:13:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_script.py:14:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_serverplayback.py:9:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_serverplayback.py:10:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_serverplayback.py:359:16: Attribute `data` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_serverplayback.py:359:36: Attribute `data` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_serverplayback.py:419:16: Attribute `status_code` on type `Response | None` is possibly unbound
- error[unresolved-attribute] test/mitmproxy/addons/test_serverplayback.py:353:22: Type `<module 'mitmproxy'>` has no attribute `test`
- error[unresolved-attribute] test/mitmproxy/addons/test_serverplayback.py:374:22: Type `<module 'mitmproxy'>` has no attribute `test`
- error[unresolved-attribute] test/mitmproxy/addons/test_serverplayback.py:389:22: Type `<module 'mitmproxy'>` has no attribute `test`
- error[unresolved-attribute] test/mitmproxy/addons/test_serverplayback.py:413:22: Type `<module 'mitmproxy'>` has no attribute `test`
- error[unresolved-import] test/mitmproxy/addons/test_stickyauth.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_stickyauth.py:6:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_stickycookie.py:4:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_stickycookie.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_stickycookie.py:6:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_strip_dns_https_records.py:6:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_strip_dns_https_records.py:7:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_strip_dns_https_records.py:8:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_stickycookie.py:31:13: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_stickycookie.py:45:9: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_stickycookie.py:96:17: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_strip_dns_https_records.py:51:31: Attribute `answers` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_strip_dns_https_records.py:77:20: Attribute `answers` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_strip_dns_https_records.py:81:20: Attribute `answers` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_strip_dns_https_records.py:83:13: Attribute `answers` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_strip_dns_https_records.py:85:20: Attribute `answers` on type `DNSMessage | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/addons/test_termlog.py:8:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_tlsconfig.py:21:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_update_alt_svc.py:4:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_update_alt_svc.py:5:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_update_alt_svc.py:28:13: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_update_alt_svc.py:36:13: Attribute `headers` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_update_alt_svc.py:43:13: Attribute `headers` on type `Response | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/addons/test_upstream_auth.py:8:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_upstream_auth.py:9:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_view.py:7:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/addons/test_view.py:8:6: Cannot resolve imported module `mitmproxy.test`
+ error[invalid-argument-type] test/mitmproxy/addons/test_view.py:54:35: Argument to function `len` is incorrect: Expected `Sized`, found `bytes | None`
+ error[invalid-argument-type] test/mitmproxy/addons/test_view.py:54:65: Argument to function `len` is incorrect: Expected `Sized`, found `bytes | None`
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_view.py:54:65: Attribute `raw_content` on type `Response | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/addons/test_view.py:71:31: Attribute `size` on type `DNSMessage | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/contentviews/test___init__.py:7:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/contentviews/test___init__.py:8:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/contentviews/test__api.py:9:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/contentviews/test__utils.py:8:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/contentviews/test__utils.py:9:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/contentviews/test__utils.py:22:13: Attribute `headers` on type `Response | None` is possibly unbound
+ error[invalid-argument-type] test/mitmproxy/contentviews/test__utils.py:23:38: Argument to function `make_metadata` is incorrect: Expected `Message | TCPMessage | UDPMessage | WebSocketMessage | DNSMessage`, found `Response | None`
+ warning[possibly-unbound-attribute] test/mitmproxy/contentviews/test__utils.py:47:19: Attribute `messages` on type `WebSocketData | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/contentviews/test__view_http3.py:6:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/contentviews/test__view_query.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/contentviews/test__view_socketio.py:8:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/proxy/bench.py:14:7: Cannot resolve imported module `.layers.http`
- error[unresolved-import] test/mitmproxy/proxy/bench.py:15:7: Cannot resolve imported module `.layers.http`
- error[unresolved-import] test/mitmproxy/proxy/layers/test_modes.py:35:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/proxy/layers/test_modes.py:36:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/proxy/test_context.py:2:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/proxy/test_context.py:3:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/proxy/test_mode_servers.py:20:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/script/test_concurrent.py:7:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/script/test_concurrent.py:8:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_addonmanager.py:13:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_addonmanager.py:14:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_command.py:11:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_command.py:12:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_dns.py:9:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_dns.py:10:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/test_dns.py:338:16: Attribute `get_state` on type `DNSMessage | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/test_dns.py:346:16: Attribute `get_state` on type `Error | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/test_eventsequence.py:5:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/test_eventsequence.py:39:16: Attribute `messages` on type `WebSocketData | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/test_eventsequence.py:41:16: Attribute `messages` on type `WebSocketData | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/test_eventsequence.py:43:16: Attribute `messages` on type `WebSocketData | None` is possibly unbound
+ warning[possibly-unbound-attribute] test/mitmproxy/test_eventsequence.py:45:16: Attribute `messages` on type `WebSocketData | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/test_flow.py:13:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_flow.py:14:6: Cannot resolve imported module `mitmproxy.test`
+ error[invalid-assignment] test/mitmproxy/test_flow.py:39:9: Object of type `Literal[True]` is not assignable to attribute `marked` of type `str`
+ error[invalid-assignment] test/mitmproxy/test_flow.py:62:9: Object of type `Literal[200]` is not assignable to attribute `status_code` on type `Response | None`
+ error[invalid-assignment] test/mitmproxy/test_flow.py:66:9: Object of type `Literal[201]` is not assignable to attribute `status_code` on type `Response | None`
- error[unresolved-import] test/mitmproxy/test_flowfilter.py:8:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_taddons.py:1:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_tcp.py:5:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/test_tcp.py:40:16: Attribute `get_state` on type `Error | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/test_types.py:12:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_types.py:13:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/test_udp.py:5:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/test_udp.py:40:16: Attribute `get_state` on type `Error | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/test_websocket.py:6:6: Cannot resolve imported module `mitmproxy.test`
+ warning[possibly-unbound-attribute] test/mitmproxy/test_websocket.py:20:30: Attribute `_get_formatted_messages` on type `WebSocketData | None` is possibly unbound
- error[unresolved-import] test/mitmproxy/tools/console/test_commander.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/tools/console/test_common.py:3:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/tools/console/test_contentview.py:4:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/tools/console/test_flowview.py:2:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/tools/console/test_keymap.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/tools/web/test_app.py:17:6: Cannot resolve imported module `mitmproxy.test`
+ error[invalid-assignment] test/mitmproxy/tools/web/test_app.py:69:9: Object of type `None` is not assignable to attribute `content` on type `Response | None`
- error[unresolved-import] test/mitmproxy/tools/web/test_static_viewer.py:7:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/tools/web/test_static_viewer.py:8:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/tools/web/test_webaddons.py:4:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] test/mitmproxy/utils/test_magisk.py:5:6: Cannot resolve imported module `mitmproxy.test`
- error[unresolved-import] web/gen/tflow_js.py:10:6: Cannot resolve imported module `mitmproxy.test`
+ error[invalid-assignment] web/gen/tflow_js.py:31:5: Object of type `Headers` is not assignable to attribute `trailers` on type `Response | None`
- Found 2124 diagnostics
+ Found 2112 diagnostics

optuna (https://github.com/optuna/optuna)
- error[unresolved-import] optuna/storages/_grpc/client.py:30:10: Cannot resolve imported module `optuna.storages._grpc.auto_generated`
- error[unresolved-import] optuna/storages/_grpc/client.py:31:10: Cannot resolve imported module `optuna.storages._grpc.auto_generated`
- error[unresolved-import] optuna/storages/_grpc/server.py:16:10: Cannot resolve imported module `optuna.storages._grpc.auto_generated`
- error[unresolved-import] optuna/storages/_grpc/servicer.py:23:10: Cannot resolve imported module `optuna.storages._grpc.auto_generated`
- error[unresolved-import] optuna/storages/_grpc/servicer.py:24:10: Cannot resolve imported module `optuna.storages._grpc.auto_generated`
- Found 1072 diagnostics
+ Found 1067 diagnostics

rclip (https://github.com/yurijmikhalevich/rclip)
- error[unresolved-import] rclip/main.py:13:6: Cannot resolve imported module `rclip`
- error[unresolved-import] rclip/main.py:17:6: Cannot resolve imported module `rclip.utils`
- error[unresolved-import] rclip/model.py:8:6: Cannot resolve imported module `rclip.utils`
- Found 16 diagnostics
+ Found 13 diagnostics

cwltool (https://github.com/common-workflow-language/cwltool)
+ error[unresolved-attribute] cwltool/main.py:188:17: Type `<module 'ruamel.yaml'>` has no attribute `comments`
+ error[unresolved-attribute] cwltool/main.py:189:22: Type `<module 'ruamel.yaml'>` has no attribute `comments`
+ error[unresolved-attribute] cwltool/main.py:245:23: Type `<module 'ruamel.yaml'>` has no attribute `comments`
+ error[unresolved-attribute] cwltool/main.py:331:16: Type `<module 'ruamel.yaml'>` has no attribute `comments`
+ error[unresolved-attribute] cwltool/main.py:747:5: Type `<module 'ruamel.yaml'>` has no attribute `representer`
- Found 297 diagnostics
+ Found 302 diagnostics

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- error[unresolved-import] benchmarks/bm/iast_utils/aspects_benchmarks_generate.py:11:6: Cannot resolve imported module `benchmarks.bm.iast_fixtures`
- error[unresolved-import] benchmarks/bm/iast_utils/aspects_benchmarks_generate.py:12:6: Cannot resolve imported module `benchmarks.bm.iast_fixtures`
- error[unresolved-import] benchmarks/bm/iast_utils/aspects_benchmarks_generate.py:13:6: Cannot resolve imported module `benchmarks.bm.iast_fixtures`
- error[unresolved-import] ddtrace/contrib/internal/celery/signals.py:11:6: Cannot resolve imported module `ddtrace.contrib.internal.celery`
- error[unresolved-import] ddtrace/contrib/internal/django/patch.py:206:5: Cannot resolve imported module `.`
- error[unresolved-import] ddtrace/contrib/internal/django/patch.py:430:5: Cannot resolve imported module `.`
- error[unresolved-import] ddtrace/contrib/internal/django/patch.py:467:5: Cannot resolve imported module `.`
- error[unresolved-import] ddtrace/contrib/internal/django/patch.py:614:5: Cannot resolve imported module `.`
- error[unresolved-import] ddtrace/contrib/internal/django/patch.py:906:5: Cannot resolve imported module `.`
- error[unresolved-import] ddtrace/contrib/internal/grpc/aio_client_interceptor.py:21:6: Cannot resolve imported module `ddtrace.contrib.internal.grpc`
- error[unresolved-import] ddtrace/contrib/internal/grpc/aio_client_interceptor.py:22:6: Cannot resolve imported module `ddtrace.contrib.internal.grpc`
- error[unresolved-import] ddtrace/contrib/internal/grpc/aio_server_interceptor.py:23:6: Cannot resolve imported module `ddtrace.contrib.internal.grpc`
- error[unresolved-import] ddtrace/contrib/internal/grpc/client_interceptor.py:14:6: Cannot resolve imported module `ddtrace.contrib.internal.grpc`
- error[unresolved-import] ddtrace/contrib/internal/grpc/client_interceptor.py:15:6: Cannot resolve imported module `ddtrace.contrib.internal.grpc`
- error[unresolved-import] ddtrace/contrib/internal/grpc/patch.py:5:6: Cannot resolve imported module `ddtrace.contrib.internal.grpc`
- error[unresolved-import] ddtrace/contrib/internal/grpc/patch.py:6:6: Cannot resolve imported module `ddtrace.contrib.internal.grpc`
- error[unresolved-import] ddtrace/contrib/internal/grpc/server_interceptor.py:11:6: Cannot resolve imported module `ddtrace.contrib.internal.grpc`
- error[unresolved-import] ddtrace/contrib/internal/grpc/utils.py:6:6: Cannot resolve imported module `ddtrace.contrib.internal.grpc`
- error[unresolved-import] ddtrace/contrib/internal/openai/patch.py:7:6: Cannot resolve imported module `ddtrace.contrib.internal.openai`
- error[unresolved-import] ddtrace/contrib/internal/protobuf/patch.py:1:6: Cannot resolve imported module `google`
+ error[unresolved-attribute] ddtrace/contrib/internal/protobuf/patch.py:30:5: Unresolved attribute `_datadog_patch` on type `<module 'google.protobuf'>`.
+ error[unresolved-attribute] ddtrace/contrib/internal/protobuf/patch.py:40:9: Unresolved attribute `_datadog_patch` on type `<module 'google.protobuf'>`.
+ error[unresolved-attribute] ddtrace/contrib/internal/protobuf/patch.py:42:16: Type `<module 'google.protobuf'>` has no attribute `internal`
- error[unresolved-import] ddtrace/contrib/internal/tornado/application.py:7:6: Cannot resolve imported module `ddtrace.contrib.internal.tornado`
- error[unresolved-import] ddtrace/contrib/internal/tornado/patch.py:12:1: Cannot resolve imported module `.`
- error[unresolved-import] ddtrace/contrib/internal/tornado/patch.py:13:1: Cannot resolve imported module `.`
- error[unresolved-import] ddtrace/contrib/internal/tornado/patch.py:14:1: Cannot resolve imported module `.`
- error[unresolved-import] ddtrace/contrib/internal/tornado/patch.py:15:1: Cannot resolve imported module `.`
- error[invalid-assignment] ddtrace/contrib/internal/tornado/patch.py:54:5: Object of type `Unknown` is not assignable to attribute `_wrap_executor` on type `Unknown | Tracer`
+ error[invalid-assignment] ddtrace/contrib/internal/tornado/patch.py:54:5: Object of type `def wrap_executor(tracer, fn, args, kwargs, span_name, service=None, resource=None, span_type=None) -> Unknown` is not assignable to attribute `_wrap_executor` on type `Unknown | Tracer`
- error[unresolved-import] tests/ci_visibility/api/fake_runner_all_itr_skip_suite_level.py:10:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_suite_level.py:30:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_suite_level.py:31:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_suite_level.py:32:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_suite_level.py:45:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_suite_level.py:46:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_suite_level.py:47:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-import] tests/ci_visibility/api/fake_runner_all_itr_skip_test_level.py:8:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_test_level.py:26:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_test_level.py:27:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_test_level.py:28:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_test_level.py:42:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_test_level.py:43:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_all_itr_skip_test_level.py:44:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-import] tests/ci_visibility/api/fake_runner_atr_mix_fail.py:17:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-import] tests/ci_visibility/api/fake_runner_atr_mix_pass.py:13:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-import] tests/ci_visibility/api/fake_runner_efd_all_pass.py:17:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-import] tests/ci_visibility/api/fake_runner_efd_faulty_session.py:15:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-import] tests/ci_visibility/api/fake_runner_efd_mix_fail.py:17:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-import] tests/ci_visibility/api/fake_runner_efd_mix_pass.py:17:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-import] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:28:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:56:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:57:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:58:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:60:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:63:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:66:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:86:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:87:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:90:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:93:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:96:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:99:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:103:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:126:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:127:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:128:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:130:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:131:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:132:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:163:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:164:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:165:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:167:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:168:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_suite_level.py:169:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-import] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:25:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:52:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:53:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:54:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:56:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:59:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:62:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:82:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:83:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:86:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:89:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:92:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:95:40: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:99:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:122:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:123:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:124:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:126:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:127:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:128:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:159:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:160:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:161:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:163:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:164:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/fake_runner_mix_fail_itr_test_level.py:165:25: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-import] tests/ci_visibility/api/test_internal_test_visibility_api.py:5:6: Cannot resolve imported module `ddtrace.internal.test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/test_internal_test_visibility_api.py:49:33: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/test_internal_test_visibility_api.py:52:37: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/test_internal_test_visibility_api.py:57:53: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/test_internal_test_visibility_api.py:83:37: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/test_internal_test_visibility_api.py:86:41: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/api/test_internal_test_visibility_api.py:92:21: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1262:9: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1293:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1294:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1295:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1296:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1297:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1300:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1303:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1307:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1308:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1309:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1310:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1311:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1314:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1317:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1324:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1325:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1326:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1327:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1328:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1331:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1334:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1338:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1339:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1340:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1341:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1342:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1345:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1348:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1353:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1354:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1355:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1356:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1357:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1360:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1363:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1366:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1367:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1368:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1369:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1370:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1373:16: Type `<module 'ddtrace.internal'>` has no attribute `test_visibility`
- error[unresolved-attribute] tests/ci_visibility/test_ci_visibility.py:1376:16: Type `<...*[Comment body truncated]*
author_association: CONTRIBUTOR
user: login: MichaReiser
created_at: 2025-05-16T15:25:15Z
body: Looks like I messed something up 😆 
author_association: MEMBER
user: login: github-actions[bot]
created_at: 2025-05-16T16:25:16Z
body: <!-- generated-comment ecosystem -->
## `ruff-ecosystem` results
### Linter (stable)
✅ ecosystem check detected no linter changes.

### Linter (preview)
✅ ecosystem check detected no linter changes.



author_association: CONTRIBUTOR
user: login: MichaReiser
created_at: 2025-05-16T17:27:03Z
body: Rotki: The output looks correct. There's a local folder called [`packaging`](https://github.com/rotki/rotki/tree/develop/packaging) that doesn't contain any python files (docker image).

The problem for `psycopg` is that its `src.root` is [`psycopg`](https://github.com/psycopg/psycopg/tree/master/psycopg) (the code is in `psycopg/psycopg`). This obviously confuses the module resolver a good deal because it now assumes that `psycopg` is a namespace package. This isn't worse than before where all imports simply failed. The solution here is to teach mypy primer to pass the `src.root` config (CC: @sharkdp ?).
author_association: MEMBER
user: login: MichaReiser
created_at: 2025-05-16T17:36:42Z
body: Mypy primer now hangs :(
author_association: MEMBER
user: login: MichaReiser
created_at: 2025-05-16T17:38:55Z
body: Something we could try is to change `src.root` to default to `.` and `<project-name>` if such a folder exists (and contains a `__init__.py`?), given that this isn't an entirely uncommon project structure.
author_association: MEMBER
user: login: AlexWaygood
created_at: 2025-05-19T19:48:46Z
body: The `schema_salad` primer hits are because we do not currently model that when an import like this occurs:

```py
import foo
from foo.bar import baz
```

then an implicit `foo.bar = <module foo.bar>` assignment occurs as a result of the second import. This is indeed unrelated to your PR -- a similar issue is discussed in https://github.com/astral-sh/ty/issues/133.
author_association: MEMBER
user: login: AlexWaygood
created_at: 2025-05-19T19:56:43Z
body: > ```diff
> + error[unresolved-attribute] examples/contrib/test_jsondump.py:10:15: Type `<module 'mitmproxy.test.tutils'>` has no attribute `test_data`
> ```

This seems like a true positive...?

```pycon
% uv run --no-project --with=mitmproxy python
      Built pyperclip==1.9.0
Installed 44 packages in 45ms
Python 3.13.1 (main, Jan  3 2025, 12:04:03) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from mitmproxy.test import tutils
>>> tutils.test_data
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    tutils.test_data
AttributeError: module 'mitmproxy.test.tutils' has no attribute 'test_data'
```

I don't really understand what's (meant to be) going on in mitmproxy's `examples/` directory at all. I think it's okay to just ignore all the (many) primer hits that are coming out of that directory...
author_association: MEMBER
user: login: MichaReiser
created_at: 2025-05-20T18:16:13Z
body: @AlexWaygood Is this good to go once I improved the comment or is there something else?
author_association: MEMBER
user: login: karlicoss
created_at: 2025-05-26T14:24:04Z
body: I have what seems like a related issue -- tried with latest ty but seems like it's still happening.


```
$ uv add --dev 'ty @ https://github.com/astral-sh/ty.git'
$ uv run ty version
ty 0.0.1-alpha.6 (55b412037 2025-05-23)
```

Wondering, has this fix made it into `ty` git version/main branch? I guess ty reuses some of the core with ruff so perhaps it's not made it through the dependencies yet?

Happy to file a separate issue in ty bugtracker if this is somehow unrelated!

# What happens
Consider the following hierarchy:
```
$ find src/testty
src/testty
src/testty/b.py
src/testty/a.py
src/testty/py.typed
```

This is the only file with code:
```
$ cat src/testty/a.py 
from testty import b
from . import b
```

This results in:
```
$ uv run ty check src/
error[unresolved-import]: Cannot resolve imported module `testty`
 --> src/testty/a.py:1:6
  |
1 | from testty import b
  |      ^^^^^^
2 | from . import b
  |
info: make sure your Python environment is properly configured: https://github.com/astral-sh/ty/blob/main/docs/README.md#python-environment
info: rule `unresolved-import` is enabled by default

error[unresolved-import]: Cannot resolve imported module `.`
 --> src/testty/a.py:2:1
  |
1 | from testty import b
2 | from . import b
  | ^^^^^^^^^^^^^^^
  |
info: rule `unresolved-import` is enabled by default

Found 2 diagnostics
```

# Expected behaviour

- this works under mypy:
  ```
  $ uv run -m mypy -p testty 
  Success: no issues found in 3 source files
  ```

- this works in ty if we convert a package from a namespace to regular one by adding `__init__.py`
  ```
  $ touch src/testty/__init__.py
  $ uv run ty check src/
  WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
  All checks passed!
  ```
author_association: NONE
user: login: nojaf
created_at: 2025-05-26T14:26:54Z
body: @karlicoss I don't believe a new version with this fix has been released yet.
author_association: NONE
user: login: sharkdp
created_at: 2025-05-26T18:58:42Z
body: @karlicoss Should be available in [ty 0.0.1-alpha.7](https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.7).
author_association: CONTRIBUTOR
user: login: karlicoss
created_at: 2025-05-26T21:24:08Z
body: Thank you, that was fast! Can confirm it works
author_association: NONE