Path handling on case-insensitive file systems #16440
Replies: 7 comments 3 replies
-
Keeping the virtual file-system (
|
Beta Was this translation helpful? Give feedback.
-
What does Pyright do?I don't understand what Pyright does in full detail but it has a What it does is roughly to canonicalize the path and use that path unless it is a symlink. Pyright calls The main downside of this approach is that it requires a Pyright can skip the Mypy does something similar in their module resolver code with the exception that |
Beta Was this translation helpful? Give feedback.
-
What does TypeScript do?TypeScript also uses a similar approach to detect if the file system is case sensitive (we should probably say that Pyright uses a similar approach to TypeScript): The flag is then passed through to different functions: E.g. matching files TypeScript is similar to Pyright in that it uses a You can see how the method is a no-op on case sensitive systems but TypeScript lower cases path on all other systems. |
Beta Was this translation helpful? Give feedback.
-
What does CPython doThat's very important for us because we want to model CPython's module resolver as accurately as possible. CPython's module resolver is case sensitive (with few legacy exceptions). That means, you can't import a module I looked into what CPython does and it seems it caches the real file names per directory and resolves those names exactly once. Using For some more details, see #13691 (comment) |
Beta Was this translation helpful? Give feedback.
-
Updating the files that are part of the projectThis seems to be the most challenging problem. Let's say you run
Red Knot will pick up the What's unclear to me is how we'd handle an event that a new file @sharkdp do you have an idea for how we could avoid knowing whether the file system is case-sensitive in this case? Removing is another case that requires special handling, but we can rely on the file system to determine the right "steps."
The only thing we'd have to be extra careful about is avoiding interning two paths for the same One downside of this approach (unless we respect the casing anyway) is that |
Beta Was this translation helpful? Give feedback.
-
TLDR: I'm leaning towards adding a The extra cost for CLI arguments should be negligible because most CLI invocations only have a few paths. The biggest added overhead comes from the module resolver but it seems that Python's forcing our hand and that we have to perform this check. |
Beta Was this translation helpful? Give feedback.
-
One use case that seems very common is that someone would rename a file from e.g. Seems like rust-analyzer and/or VS code have/had problems with this: rust-lang/rust-analyzer#9581 rust-lang/rust-analyzer#9947 rust-lang/rust-analyzer#15300 |
Beta Was this translation helpful? Give feedback.
-
Discussion related to #16400
I am starting this discussion to provide some more background on the problem with case-insensitive file systems and discuss different approaches.
The fundemental problems are:
knot check SRC
in a project with asrc
folder and Red Knot will happily index the files in thesrc
folder on case-insensitive file systems. However, the constructed paths useSRC/a.py
instead ofsrc/a.py
because the syscall to list a directory doesn't return full paths for its files but only relative paths that Red Knot concatenates with the user-provided path.from C import C
fails if the module on this isc.py
even on mac os (see Audit how we determine whether a file is a "Python source file" #13691). According to that issue, Mypy has special handling for this and it seems so does Pyright (because it raises an error for the previously given example).How can these incorrect paths manifest:
knot check <PATHS>
TEST/a.py
when runningknot check TEST
even if the folder's real name istest
.Whatever solution we end up with, we should optimize for the case where file paths are unique, ignoring their casing. It should be extremely rare to find projects with files that only differ in their casing, considering that the two popular platforms Windows and MacOS don't support it by default and it can be fairly confusing for devs.
Beta Was this translation helpful? Give feedback.
All reactions