Python: Fix resolution of relative imports from namespace packages

The fix may look a bit obscure, so here's what's going on.

When we see `from . import helper`, we create an `ImportExpr` with level
equal to 1 (corresponding to the number of dots). To resolve such
imports, we compute the name of the enclosing package, as part of
`ImportExpr.qualifiedTopName()`. For this form of import expression, it
is equivalent to `this.getEnclosingModule().getPackageName()`. But
`qualifiedTopName` requires that `valid_module_name` holds for its
result, and this was _not_ the case for namespace packages.

To fix this, we extend `valid_module_name` to include the module names
of _any_ folder, not just regular package (which are the ones where
there's a `__init__.py` in the folder). Note that this doesn't simply
include all folders -- only the ones that result in valid module names
in Python.
This commit is contained in:
Taus
2026-03-11 23:02:09 +00:00
parent 48bf4fd82a
commit e16bb226c0
2 changed files with 5 additions and 1 deletions

View File

@@ -17,6 +17,10 @@ private predicate valid_module_name(string name) {
exists(Module m | m.getName() = name)
or
exists(Builtin cmod | cmod.getClass() = Builtin::special("ModuleType") and cmod.getName() = name)
or
// Namespace packages may not have a corresponding Module entity,
// but their names are still valid for the purpose of import resolution.
name = moduleNameFromFile(any(Folder f))
}
/** An artificial expression representing an import */

View File

@@ -1,2 +1,2 @@
def process(value):
sink(value) #$ MISSING: prints=source
sink(value) #$ prints=source