False `missing-source` when stubs are on `search-path` and the source is in site-packages
- Dominant language
- Rust
- Stars
- 7k
- Forks
- 519
- PR merge metrics
- No merged PRs in 30d
Description
pyrefly 1.2.0 · Windows 11 · CPython 3.14
If a PEP 561 stub-only package `foo-stubs/` is found on `search-path`, pyrefly does not
look in `site-package-path` for the runtime `foo/`, and reports `missing-source` even
though the package is installed and importable.
## Repro
`foo` is placed in a real venv's site-packages, so it is genuinely importable; the venv is
auto-detected, no `python-interpreter` setting needed.
```bash
mkdir repro && cd repro
python -m venv .venv
PY=$([ -x .venv/bin/python ] && echo .venv/bin/python || echo .venv/Scripts/python.exe)
SP=$("$PY" -c "import sysconfig;print(sysconfig.get_paths()['purelib'])")
mkdir -p "$SP/foo" foo-stubs
printf 'def f():\n return 1\n' > "$SP/foo/__init__.py"
printf 'def f() -> int: ...\n' > foo-stubs/__init__.pyi
printf 'import foo\n' > main.py
printf 'search-path = ["."]\nproject-includes = ["main.py"]\n' > pyrefly.toml
"$PY" -c "import foo; print('runtime import OK:', foo.__file__)"
pyrefly check --preset all
```
```powershell
mkdir repro; cd repro
python -m venv .venv
$PY = ".venv\Scripts\python.exe"
$SP = & $PY -c "import sysconfig;print(sysconfig.get_paths()['purelib'])"
New-Item -ItemType Directory -Force "$SP\foo", foo-stubs | Out-Null
@'
def f():
return 1
'@ | Set-Content "$SP\foo\__init__.py"
'def f() -> int: ...' | Set-Content foo-stubs\__init__.pyi
'import foo' | Set-Content main.py
@'
search-path = ["."]
project-includes = ["main.py"]
'@ | Set-Content pyrefly.toml
& $PY -c "import foo; print('runtime import OK:', foo.__file__)"
pyrefly check --preset all
```
The `import foo` line succeeds, printing the path inside `.venv`. pyrefly nevertheless
reports:
```
ERROR Found stubs for `foo`, but no source. This means it's likely not installed/unimportable. [missing-source]
--> main.py:1:8
|
1 | import foo
| ^^^
```
Expected: 0 errors.
## Where the lookup stops
Moving only the two packages (verified both with a real venv and with a plain directory
declared via `site-package-path`, which behave identically):
| Stubs in | Source in | Result |
|---|---|---|
| `search-path` | `site-package-path` | **error** |
| `search-path` | `site-package-path`, + `py.typed` | **error** |
| `search-path` | `search-path`, same root | ok |
| `site-package-path` | `site-package-path`, same root | ok |
| `search-path` root #1 | `search-path` root #2 | ok |
| `site-package-path` #1 | `site-package-path` #2 | ok |
The lookup spans multiple roots *within* a category; only the cross-category case fails.
`py.typed` makes no difference. Pure-`.py` and compiled `.pyd` submodules fail
identically, so this isn't extension-module handling — `.pyd` is correctly recognised as
source when it shares a root with its stub.
Contributor guide
Research direction
Start with the provided real-venv reproduction using pyrefly.toml, main.py, and `pyrefly check --preset all`; compare lookup behavior across search-path and site-package-path. Trace the package resolution entry point for stub-only packages and make the cross-category case find the runtime source, while preserving the listed same-category cases. Done means the reproduction reports 0 errors on Windows and the other demonstrated layouts remain correct.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, rust
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100