Import Resolution
This doc describes how imports in a given file are found and their bindings are resolved, including files that are being type checked.
NOTE: see the Configuration documentation for more info on the config items referenced below.
Relative Imports
If the import is relative (starting with one or more dots), the import is
resolved relative to the path of the file importing it. A single dot at the
beginning of the import (e.g. .file.to.import
) represents the current
directory, and more dots (e.g. ..other.file
) will continue to walk upward.
Absolute Imports
For absolute imports, Pyrefly uses the following import strategy:
- Try to import from each entry in
search_path
in the order they appear using the module finding strategy. a. NOTE: we append the config file's directory tosearch_path
automatically when using a config file as a sensible last-resort for attempting an import. - Try to import from
typeshed
. - Try to find a stub package corresponding to the import we're trying to resolve in
site_package_path
. Entries earlier in thesite_package_path
list will be selected before those appearing later in the list. See the typing spec for more info on stub packages.- If we find a
-stubs
package, but there's no non-stubs package, return an import error.
- If we find a
- Try to find a non-stub package corresponding to the import we're trying to resolve in
site_package_path
. Entries earlier in thesite_package_path
list will be selected before those appearing later in the list. - Return an import error.
See Site Package Path Typing Rules for more information about which
modules are valid imports from site_package_path
, and
how to override that behavior.
Site Package Path Typing Rules
We respect typing rules as defined by the typing spec for stubs packages, partial stubs packages, and py.typed files. That means:
- if we can find any
-stubs
package, we do not fall back to non-stubs packages unless any of them contain apy.typed
file in their top-level containing the contentpartial\n
. - if we can't find any
-stubs
packages, only accept a package's types if it contains apy.typed
file. Here, we only check for the existence of the file, not for any contents.
You can control the above behavior with the following two configs:
use_untyped_imports
: don't worry about looking for anypy.typed
file. Check for-stubs
first and fall back to non-stubs, regardless of the presence of apy.typed
withpartial\n
or if the non-stubs packages contain apy.typed
.ignore_missing_source
: don't try to check for a backing non-stubs package when we find a-stubs
pacakge. Immediately return the-stubs
package when found.
Stub Files vs Source Files
A
stub file
is any file that ends with a .pyi
file suffix. They have many uses, including
adding typing to non-Python extension code, distributing typing information
separate from implementation, or overriding an implementation with more accurate
typing information.
A stub package is a second package corresponding to a regular package, with -stubs
appended to its name. A -stubs
package should only include stub files (.pyi
),
which override any .py
or .pyi
files in the non-stubs package. These are preferred
when available, since they contain the interfaces a library exposes to developers. An
example of this includes the popular library pandas
,
and its stub package, pandas-stubs
.
When importing from a non-stubs package, Pyrefly loads typing information from
imports by first searching for a relevant -stubs
package, then by looking at
the non-stubs package's .pyi
files, then falls back to a .py
file. See
Absolute Imports for details on when non-stubs packages
are allowed to be used for types, and how you can override that behavior.