Stop treating non-file document URIs as filesystem paths - #982
Open
ZayanKhan-12 wants to merge 2 commits into
Open
ZayanKhan-12 wants to merge 2 commits into
ZayanKhan-12 wants to merge 2 commits into
Conversation
Editors that keep buffers in memory send URIs such as Monaco's
inmemory://dummy.py or VS Code's untitled:. Those have no file behind them, but
the server assumed every document did, so it derived a path and then used it for
filesystem work.
The name in inmemory://dummy.py lands in the URI authority rather than the path,
so to_fs_path returned the empty string for it. That left the document with an
empty path, filename and dot name, and three consequences followed:
- os.path.dirname('') normalizes to '.', so requesting completions with
use_document_path put the server's own working directory on Jedi's module
search path. Completions could resolve against whatever happened to be next to
the running process.
- Jedi received path='' rather than no path at all.
- Reading a document that had not been opened yet fell through to
io.open(''), raising FileNotFoundError naming a path the client never sent.
to_fs_path now keeps the authority for non-file schemes, so inmemory://dummy.py
resolves to /dummy.py and the document has a stable identity for module naming
and diagnostics. This deliberately differs from vscode-uri, which drops the
authority, and the reason is recorded next to the branch. File URIs, UNC paths
and Windows drive letters are unchanged.
Adds uris.is_file_uri and Document.is_file_backed so callers can tell an
identifier from a location, and uses it to skip the sys.path extension and to
raise a clear error instead of reading an unrelated file.
This covers in-memory analysis of a single document. Resolving imports between
two in-memory documents needs Jedi to see them as modules and is not addressed.
Partially addresses palantir#199
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Records the things that are easy to get wrong here: the Python 2.7 and jedi<0.18 constraints that rule out a modern interpreter, the two extra pins needed for a working environment, the pre-existing test and lint failures on a clean checkout, and the distinction between a URI that has a file behind it and one that does not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Member
|
Thanks for your interest in palantir/python-language-server, @ZayanKhan-12! Before we can accept your pull request, you need to sign our contributor license agreement - just visit https://cla.palantir.com/ and follow the instructions. Once you sign, I'll automatically update this pull request. |
ZayanKhan-12
pushed a commit
to ZayanKhan-12/python-language-server
that referenced
this pull request
Sep 16, 2026
Stop treating non-file document URIs as filesystem paths (palantir#199) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Partially addresses #199.
Editors that keep buffers in memory send URIs with no file behind them — Monaco's
inmemory://dummy.pyfrom the original report, and VS Code'suntitled:andvscode-notebook-cell:. The server assumed every document had a file, derived a path, and then used that path for filesystem work.The specific trigger is that
inmemory://dummy.pyputs the name in the URI authority, not the path, sourlparsegivesnetloc='dummy.py', path=''. The UNC branch into_fs_pathis gated onscheme == 'file', so the authority was dropped and the function returned the empty string:Three things followed from that empty path. The one worth highlighting is the second:
path=''rather than no path.os.path.dirname('')normalizes to'.', so asking for completions withuse_document_path=Trueput the server's own working directory on Jedi's module search path. Completions in an in-memory buffer could resolve against whatever happened to sit next to the running process. Verified by capturing thesys_pathhanded tojedi.Project.io.open(''), raisingFileNotFoundError: ''— an error naming a path the client never sent.Changes
to_fs_pathkeeps the authority for non-file schemes, soinmemory://dummy.pyresolves to/dummy.pyand the document has a stable identity for module naming and diagnostics.This deliberately differs from
vscode-uri, which drops the authority and returns the empty path. Since the module docstring points atvscode-uriand a reader may well diff the two, the reason is recorded in a comment next to the branch. File URIs, UNC paths and Windows drive letters are untouched:Adds
uris.is_file_uri()andDocument.is_file_backedso callers can tell a path-shaped identifier from an actual location, then uses it to skip thesys.pathextension for non-file documents and to raise a clear error instead of reading an unrelated file.Scope
This covers in-memory analysis of a single document, which is what @gatesn asked about in the thread ("purely in-memory analysis, e.g. only things passed by didOpen").
It does not implement what @ColinTenaguillo asked for in 2022 — importing between two in-memory documents. That needs Jedi to see unsaved buffers as importable modules, which means a custom project or importer rather than a URI fix, and I did not want to bundle it into this change. Flagging it so the issue is not closed as fully resolved on the strength of this PR.
Tests
16 new tests across
test/test_uris.pyandtest/test_document.py: the URI translations above,is_file_uriacross schemes, the document properties, thesys.pathbehaviour for both document kinds, the error when an unopened non-file document is read, and a completion inside an in-memory document.I checked the tests actually hold the line by re-breaking each fix in turn: reverting the authority handling fails 3, restoring the
sys.pathinjection fails 1, removing the source guard fails 1.Verification
Run on Python 3.8 with
jedi 0.17.2, matching the CI matrix.A clean checkout of
developdoes not produce a clean run, so I recorded a baseline first and compared:pytest test/pycodestyle pyls testpyflakes pyls test_utils.py)The 12 failures are pre-existing and track linter versions that moved on since 2020 (flake8, pydocstyle, pylint, numpy hover). None are touched by this change.
pylint pyls testgoes from 84 messages to 92. The eight added are 6 ×redundant-u-string-prefixand 2 ×consider-using-f-string, both of which the Python 2.7 support in this repo requires and both already present in the baseline. I fixed the one genuinely new message I introduced, awrong-import-ordercaused bytestshadowing a stdlib name.Two environment pins were needed to get the suite running at all, neither related to this change:
setuptools<70(pkg_resourceswas removed) andpylint<3(pylint.epylintwas removed). Both are captured in theCLAUDE.mdadded in the second commit, which is independent — happy to drop that commit if it is not wanted.