`foo` vs `foo-stubs` with MYPYPATH

Distributing type information — typing documentation says

The name of the stub package MUST follow the scheme foopkg-stubs for type stubs for the package named foopkg

Is this only the case with stubs packages installed to site-packages?

I created a subdirectory for my project-specific stubs:

typings
└── foo-stubs
    └── __init__.pyi

and ran mypy with MYPYPATH=typings. I expected mypy to accept “import foo”, but it said

Cannot find implementation or library stub for module named "foo"  [import-not-found]

Please note, that at this point neither the environment nor stubs directory contained an implementation for package “foo”, only stubs. Is mypy expected to accept stubs without implementation?

Anyway, then I tried adding a dummy implementation:

typings
└── foo-stubs
    └── __init__.pyi
└── foo
    └── __init__.py

Now mypy was happy with “import foo” and curiously, it also started using the types from the “foo-stubs” directory, which I did not touch.

Then I removed the implementation and removed the “-stubs” suffix from stubs package:

typings
└── foo
    └── __init__.pyi

mypy was happy with this.

So, I’ve found the solution, but the confusion remained. This solution seems to contradict PEP561 and several suggestions I’ve seen elsewhere, where people had fixed their problems by adding the “-stubs” suffix to their stub package directories.

Have I misunderstood PEP561? Is this issue specific to MyPy? Or is it specific to MYPYPATH?

I have similar issues when running mypy or stubtest on scipy-stubs. If I remember correctly, I believe that it was related to uv’s editable installs (when I was still using python-poetry, I didn’t have this issue). I tried many different build backends and build configurations, but none of them helped. I’m still not sure whether this issue is caused by mypy, uv, my build backend (hatch), or something else. But when I run pyright, for example, I don’t have this issue.

The workaround I’m now using is to run uv run --no-editable --isolated --refresh-package=scipy-stubs mypy --config-file=pyproject.toml . (instead of uv run mypy.). It’s far from ideal, as it’s a long command, it’s quite a bit slower, and it requires additional configuration to get working in your IDE (vscode in my case).

Anyway, I’m not sure if this is relevant to your situation, but maybe his can be of some help :man_shrugging:.

I did some digging, and apparently mypy doesn’t properly work with editable dependencies, and there’s no plan to support this: Support finding "editable" type annotated packages made editable through direct_url.json · Issue #12313 · python/mypy · GitHub

Related uv discussions:

This isn’t unique to mypy and no type checker I’m aware of plans to support import hooks which some editable installs use. Pyright similarly does not handle import hook based editables. Type checkers are based on static analysis. Import hooks are not static.

To clarify this a little, mostly because it confused me when you put it this way, mypy (and other type checkers) need static type information, and to get that from installed packages they need to be able to statically find the sources for any imports.

Until 3-4 years ago, “editable installs” were implemented by setuptools using a .pth file, which listed where to get the package source from. While this was technically calculated at runtime, the file format was sufficiently straightforward that type checkers could (and did, I believe) special-case it and find the package at type-checking time.

When PEP 660 was implemented, this allowed all projects to have editable installs, not just setuptools. It did so by allowing the “build backend”[1] to implement the mechanism for making the package available. The option to use the old (type checker compatible) .pth file approach was still there, but the various build tools chose (for better or worse) to use a more dynamic approach, using import hooks. That is less error-prone than the .pth file at runtime, but unfortunately, it’s too dynamic for type checkers.

It is possible to fix this. Build tools could include a file in the install that describes to static type checkers where to find typing information. It would need someone to define a standard for such a file, and a PEP requiring tools that implement the editable install API to include that file in the installed package, but there’s nothing theoretically preventing this. So far, though, no-one has been sufficiently interested to do that work. There was a discussion on the old typing-sig, archived here, but it ultimately fizzled out without anyone coming up with a concrete proposal. Maybe it could be restarted?


  1. which is what setuptools is ↩︎

1 Like

That’s the best explanation I’ve seen of editable installs so far, and this time I finally felt like I understood it. Thanks!

1 Like