Prefer *-stubs when finding packages
Hi, this is going to be a hand-wavy issue, sorry.
I'm excited to try ty over Pylance in VS Code. I've immediately run into an issue though.
I run VS Code, and my module, in a Rez environment. I have a wrapped C++ package (a binary called ape.pyd) that I use a lot, which has custom stubs package called ape-stubs. In the Rez environment, PYTHONPATH contains the directories for both the package containing the ape.pyd, and the directory containing ape-stubs, but the pyd directory comes first.
With Pyright/Pylance this used to work. ape-stubs was used for autocompletion etc. However ty appears to be using ape.pyd, and it's not finding any of the useful information in the stubs.
I set the log level to "trace" and saw this in the output (I'm filtering by "ape", and I've condensed the file paths. Also as you can see I have a directory junction from C to S):
2025-12-17 10:22:04.872486000 DEBUG ty:main ty_project::metadata::options: Adding `c:\path_to_pyd\packages\ape\1.0\python-3.10` from the `PYTHONPATH` environment variable to `extra_paths`
2025-12-17 10:22:04.872533100 DEBUG ty:main ty_project::metadata::options: Adding `c:\path_to_stubs` from the `PYTHONPATH` environment variable to `extra_paths`
...
2025-12-17 10:22:04.876326600 DEBUG ty:main ty_python_semantic::module_resolver::resolver: Adding extra search-path `S:\path_to_pyd\packages\ape\1.0\python-3.10`
2025-12-17 10:22:04.876435300 DEBUG ty:main ty_python_semantic::module_resolver::resolver: Adding extra search-path `S:\path_to_stubs`
...
2025-12-17 10:22:04.882233300 DEBUG ty:main ruff_db::files::file_root: Adding new file root 'S:\path_to_pyd\packages\ape\1.0\python-3.10' of kind LibrarySearchPath
2025-12-17 10:22:04.882242200 DEBUG ty:main ruff_db::files::file_root: Adding new file root 'S:\path_to_stubs' of kind LibrarySearchPath
...
2025-12-17 10:22:04.885231400 DEBUG ty:main ty_python_semantic::module_resolver::resolver: Adding editable installation to module resolution path S:\path_above_stubs
2025-12-17 10:22:04.885242800 DEBUG ty:main ruff_db::files::file_root: Adding new file root 'S:\path_above_stubs' of kind LibrarySearchPath
I think the language server should see that it has a package called ape in a search path, and ape-stubs in a later search path, and prefer ape-stubs even though it found ape first.
Our code does first search every search-path for a stub, and only then if it fails searches for non-stubs. So whatever's happening here is us getting confused and not finding ape-stubs at all.
I'm certainly suspicious that the junction's making us get confused. I'm also suspicious about the fact that S:\path_to_stubs and S:\path_above_stubs are both things you list in your output. That's a common recipe for us getting confused (https://github.com/astral-sh/ty/issues/1730)
Thanks for that info. I can attempt some other things to see if I can narrow the junction part down, at least. Regarding that, the recent change to the VS Code "python.locator" broke the PyLance language server for me and I have to use the setting "python.locator": "js" (rather than native) for that to work correctly.
Regarding the path I labeled as path_above_stubs, I'm not sure where that is coming from. It is the directory above path_to_stubs (in case my shorthand is confusing). It might be coming from somewhere else in my environment that I've missed, but it doesn't have the associated line with "from the PYTHONPATH environment variable" in the log like the other paths do.
The logs suggest that path_above_stubs is an editable installed into your venv
You're correct, thanks. It's in a .pth file. I removed it and while those lines are now gone from the log, the problem of not using the stubs remains.
I have also managed to run my VS Code in a Rez environment build entirely from my S: drive, with no junctions, and I'm still getting the problem. Here's a new log summary:
2025-12-17 12:58:17.494912000 DEBUG ty:main ty_project::metadata::options: Adding `s:\path_to_pyd\packages\ape\1.0\python-3.10` from the `PYTHONPATH` environment variable to `extra_paths`
2025-12-17 12:58:17.494946300 DEBUG ty:main ty_project::metadata::options: Adding `S:\path_to_stubs` from the `PYTHONPATH` environment variable to `extra_paths`
...
2025-12-17 12:58:17.497297200 DEBUG ty:main ty_python_semantic::module_resolver::resolver: Adding extra search-path `S:\path_to_pyd\packages\ape\1.0\python-3.10`
2025-12-17 12:58:17.497379900 DEBUG ty:main ty_python_semantic::module_resolver::resolver: Adding extra search-path `S:\path_to_stubs`
...
2025-12-17 12:58:17.500628200 DEBUG ty:main ty_python_semantic::module_resolver::resolver: Using vendored stdlib
2025-12-17 12:58:17.500930300 DEBUG ty:main ty_python_semantic::module_resolver::resolver: Adding site-packages search path `S:\...\python3.10.11\Lib\site-packages`
2025-12-17 12:58:17.500994500 INFO ty:main ty_project::metadata::options: Python version: Python 3.10, platform: win32
...
2025-12-17 12:58:17.501120000 DEBUG ty:main ruff_db::files::file_root: Adding new file root 'S:\path_to_pyd\packages\ape\1.0\python-3.10' of kind LibrarySearchPath
2025-12-17 12:58:17.501128900 DEBUG ty:main ruff_db::files::file_root: Adding new file root 'S:\path_to_stubs' of kind LibrarySearchPath
...
2025-12-17 12:58:17.501762600 DEBUG ty:main ty_server::session: Registering diagnostic capability with OpenFilesOnly diagnostic mode
2025-12-17 12:58:17.501810100 DEBUG ty:main ty_python_semantic::module_resolver::resolver: Resolving dynamic module resolution paths
2025-12-17 12:58:17.502208600 DEBUG ty:main ty_python_semantic::module_resolver::resolver: Adding editable installation to module resolution path ...
...
2025-12-17 12:58:17.506657700 DEBUG ty:main ty_server::server::main_loop: Processing deferred notification `textDocument/didOpen`
2025-12-17 12:58:17.506685500 INFO ty:main notification{method="textDocument/didOpen"}: ty_server::session: Initializing the default project
2025-12-17 12:58:17.507848300 INFO ty:main notification{method="textDocument/didOpen"}: ty_project::metadata::options: Defaulting to python-platform `win32`
...
2025-12-17 12:58:17.508598800 DEBUG ty:main notification{method="textDocument/didOpen"}: ty_project::metadata::options: Adding `s:\path_to_pyd\packages\ape\1.0\python-3.10` from the `PYTHONPATH` environment variable to `extra_paths`
2025-12-17 12:58:17.508630500 DEBUG ty:main notification{method="textDocument/didOpen"}: ty_project::metadata::options: Adding `S:\path_to_stubs` from the `PYTHONPATH` environment variable to `extra_paths`
...
2025-12-17 12:58:17.510881800 DEBUG ty:main notification{method="textDocument/didOpen"}: ty_python_semantic::module_resolver::resolver: Adding extra search-path `S:\path_to_pyd\packages\ape\1.0\python-3.10`
2025-12-17 12:58:17.510964100 DEBUG ty:main notification{method="textDocument/didOpen"}: ty_python_semantic::module_resolver::resolver: Adding extra search-path `S:\path_to_stubs`
...
2025-12-17 12:58:17.514290600 DEBUG ty:main notification{method="textDocument/didOpen"}: ty_python_semantic::module_resolver::resolver: Using vendored stdlib
2025-12-17 12:58:17.514540400 INFO ty:main notification{method="textDocument/didOpen"}: ty_project::metadata::options: Python version: Python 3.14, platform: win32
...
2025-12-17 12:58:17.514664700 DEBUG ty:main notification{method="textDocument/didOpen"}: ruff_db::files::file_root: Adding new file root 'S:\path_to_pyd\packages\ape\1.0\python-3.10' of kind LibrarySearchPath
2025-12-17 12:58:17.514673400 DEBUG ty:main notification{method="textDocument/didOpen"}: ruff_db::files::file_root: Adding new file root 'S:\path_to_stubs' of kind LibrarySearchPath
I've attached a full log, similarly redacted.
As an experiment, I copied the ape-stubs directory from S:\path_to_stubs to s:\path_to_pyd\packages\ape\1.0\python-3.10, and ty now reads the stubs correctly. I'm not sure if that will be a possible long-term fix for us, but hopefully it tells you more about the problem.
I think the issue here is simply the ordering of the paths. Could you try changing PYTHONPATH so that the stubs path comes before S:\path_to_pyd\packages\ape\1.0\python-3.10 (which should make ty try the stubs path first)
I don't think that's an option for me, because my PYTHONPATH is built by Rez.
I think the language server should see that it has a package called ape in a search path, and ape-stubs in a later search path, and prefer ape-stubs even though it found ape first. That appears to be how PyRight does it, anyhow.