Import Resolution
This doc describes how imports in a given file are found within Pyrefly while performing a type check or resolving IDE language support operations.
NOTE: see the Configuration documentation for more info on the config options 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 searches for a match in each of the following groups. The matching process is explained in the next paragraph.
- Try to import from the search path. See the search path section for more information.
- Try to import from
typeshed
. - Try to import from the fallback search path. See the fallback search path section for more information on the contents of the search path.
- Try to import from the site package path. See the site package path section for more information on the contents of the site package path.
- Return an import error.
When searching for a match in one of the above groups, Pyrefly performs the following process over two passes, one looking for stub packages, and the other looking for source packages. See Stub Files vs Source Files for more information.
- Attempt to match each part of the name to directories in the group, selecting the first match that is found.
- If the result is a
.pyi
file or regular package (directory with an__init__.py
/__init__.pyi
file), return the result. Otherwise, keep searching and attempt to find a.pyi
file or regular package.
Search Path
The search path (see search-path
in configuration docs)
consists of several entries representing project files.
- Search path from CLI args.
- Search path from config files.
- If
disable-search-path-heuristics
is not set, Pyrefly appends an import root directory to the search path.
The import root is:
src/
if there's asrc/
directory in the same directory as the config file.- The parent directory (
..
) if there's an__init__.py
or__init__.pyi
in the same directory as the config file. - Otherwise, the directory containing the config file.
Fallback Search Path
The fallback search path is a heuristic automatically constructed by Pyrefly to attempt to
find project files when there's no config file marking the project root, and Pyrefly
is unable to determine from other heuristics where an import root might be.
It is only constructed when
disable-search-path-heuristics
is not set.
The fallback search path consists of each directory from the directory containing a given file to the root of your filesystem. For example, if you have the following setup:
/
|- projects/
|- project_a/
| |- b/
| | |- c.py
| |- d.py
|- project_e/
|- f.py
c.py
's fallback search path would be ['/projects/project_a/b', '/projects/project_a', '/projects', '/']
d.py
could be importable with the pathsd
,project_a.d
, orprojects.project_a.d
.f.py
could be importable with the pathsproject_e.f
orprojects.project_e.f
.
e.py
's fallback search path would be ['/projects/project_a', '/projects', '/']
c.py
could be importable with the pathsb.c
,project_a.b.c
, orprojects.project_a.b.c
f.py
could be importable with the pathsproject_e.f
orprojects.project_e.f
f.py
's fallback search path would be ['/projects/project_e', '/projects', '/']
c.py
could be importable with the pathsproject_a.b.c
orprojects.project_a.b.c
d.py
could be importable with the pathsproject_a.d
orprojects.project_a.d
Site Package Path
The site package path
(see site-package-path
in configuration docs)
consists of several entries representing third-party packages.
- Site package path from a config file (if no CLI override is present) or CLI args.
- A site package path queried from a Python interpreter, if one could be found. See Environment Autoconfiguration for more information on finding interpreters.
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.
Editable Installs
When using static analysis tools with an editable install, the editable install should be configured to use .pth
files that contain file paths (/project/src/module
) rather than executable lines (started with import
) that
install import hooks. See setuptools doc
and PEP 660 for more information.
Import hooks can provide an editable installation that offers a more accurate representation of the actual installation environment. However, since resolving module locations through an import hook requires executing Python code at runtime, they are incompatible with Pyrefly and other static analysis tools that operate without code execution. Consequently, when an editable install is configured to use import hooks, Pyrefly will be unable to automatically locate and analyze the corresponding source files, resulting in incomplete type checking and code analysis.
Setuptools build system uses import hooks by default for editable installations. To ensure compatibility between
setuptools-based editable installs and Pyrefly, setuptools must be configured to use path-based .pth
files instead.
This configuration should be performed through the build frontend (such as pip
) by specifying the appropriate
options during installation or in the project's configuration files.
uv with setuptools
When using uv with setuptools, uv can be configured to avoid import hooks.
NOTE: The uv_build
backend always uses path-based .pth
files.
pip with setuptools
When using pip
with setuptools-based projects, there are two ways to avoid import hooks:
compat mode
and strict mode.
Hatch / Hatchling
Hatchling uses path-based .pth
files by default.
It will only use import hooks if you set dev-mode-exact
to true.
PDM
PDM uses path-based .pth
files by default.
It will only use import hooks if you set
editable-backend
to "editables".
Poetry / Poetry-core
Poetry-core backend always uses path-based .pth
files.
Debugging Import Issues
Pyrefly has a dump-config
command that dumps the import-related config options it is using for
each file it is checking. To use it, simply replace check
with dump-config
in your
command-line invocation.