Commit graph

37 commits

Author SHA1 Message Date
Micha Reiser
b51c4f82ea
Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00
David Peter
5fef4d4572
Use python.typing.org for typing documentation links (#17323)
## Summary

There is a new official URL for the typing documentation:
https://typing.python.org/

Change all https://typing.readthedocs.io/ links to use the new sub
domain, which is slightly shorter and looks more official.

## Test Plan

Tested to see if each and every new URL is accessible. I noticed that
some links go to https://typing.python.org/en/latest/source/stubs.html
which seems to be outdated, but that is a separate issue. The same page
shows up for the old URL.
2025-04-09 20:38:20 +02:00
Micha Reiser
6cc2d02dfa
[red-knot] Support stub packages (#17204)
## Summary

This PR adds support for stub packages, except for partial stub packages
(a stub package is always considered non-partial).

I read the specification at
[typing.python.org/en/latest/spec/distributing.html#stub-only-packages](https://typing.python.org/en/latest/spec/distributing.html#stub-only-packages)
but I found it lacking some details, especially on how to handle
namespace packages or when the regular and stub packages disagree on
whether they're namespace packages. I tried to document my decisions in
the mdtests where the specification isn't clear and compared the
behavior to Pyright.

Mypy seems to only support stub packages in the venv folder. At least,
it never picked up my stub packages otherwise. I decided not to spend
too much time fighting mypyp, which is why I focused the comparison
around Pyright

Closes https://github.com/astral-sh/ruff/issues/16612

## Test plan

Added mdtests
2025-04-07 14:40:50 +02:00
Alex Waygood
a1eb834a5f
Fix relative import resolution in site-packages packages when the site-packages search path is a subdirectory of the first-party search path (#17178)
## Summary

If a package in `site-packages` had this directory structure:

```py
# bar/__init__.py
from .a import A

# bar/a.py
class A: ...
```

then we would fail to resolve the `from .a import A` import _if_ (as is
usually the case!) the `site-packages` search path was located inside a
`.venv` directory that was a subdirectory of the project's first-party
search path. The reason for this is a bug in `file_to_module` in the
module resolver. In this loop, we would identify that
`/project_root/.venv/lib/python3.13/site-packages/foo/__init__.py` can
be turned into a path relative to the first-party search path
(`/project_root`):


6e2b8f9696/crates/red_knot_python_semantic/src/module_resolver/resolver.rs (L101-L110)

but we'd then try to turn the relative path
(.venv/lib/python3.13/site-packages/foo/__init__.py`) into a module
path, realise that it wasn't a valid module path... and therefore
immediately `break` out of the loop before trying any other search paths
(such as the `site-packages` search path).

This bug was originally reported on Discord by @MatthewMckee4.

## Test Plan

I added a unit test for `file_to_module` in `resolver.rs`, and an
integration test that shows we can now resolve the import correctly in
`infer.rs`.
2025-04-03 15:48:05 +01:00
Micha Reiser
a1535fbdbd
[red-knot] Change venv discovery (#17099)
## Summary

Rewrites the virtual env discovery to:

* Only use of `System` APIs, this ensures that the discovery will also
work when using a memory file system (testing or WASM)
* Don't traverse ancestor directories. We're not convinced that this is
necessary. Let's wait until someone shows us a use case where it is
needed
* Start from the project root and not from the current working
directory. This ensures that Red Knot picks up the right venv even when
using `knot --project ../other-dir`

## Test Plan

Existing tests, @ntBre tested that the `file_watching` tests no longer
pick up his virtual env in a parent directory
2025-03-31 19:39:05 +02:00
Matthew Mckee
0e48940ea4
[red-knot] Discover local venv folder in cli (#16917)
<!--
Thank you for contributing to Ruff! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

Fixes #16744 

Code from 

bbf4f830b5/crates/uv-python/src/virtualenv.rs (L124-L144)

## Test Plan

Manual testing

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2025-03-28 17:59:49 +00:00
Micha Reiser
7fb765d9b6
[red-knot] Log sys-prefix origin for easier debugging (#16921)
## Summary

Log the origin of the sys path prefix. This should help with debugging
if someone doesn't understand
why Red Knot picks up a certain venv.

## Test Plan

Ran the CLI and tested that it logs the origin
2025-03-23 08:06:04 +00:00
Matthew Mckee
cdafd8e32b
Allow discovery of venv in VIRTUAL_ENV env variable (#16853)
## Summary

Fixes #16744 

Allows the cli to find a virtual environment from the VIRTUAL_ENV
environment variable if no `--python` is set

## Test Plan

Manual testing, of:
- Virtual environments explicitly activated using `source .venv/bin/activate`
- Virtual environments implicilty activated via `uv run`
- Broken virtual environments with no `pyvenv.cfg` file
2025-03-20 13:55:35 +00:00
Micha Reiser
c100d519e9
[internal]: Upgrade salsa (#16794)
## Summary

Another salsa upgrade. 

The main motivation is to stay on a recent salsa version because there
are still a lot of breaking changes happening.
The most significant changes in this update:

* Salsa no longer derives `Debug` by default. It now requires
`interned(debug)` (or similar)
* This version ships the foundation for garbage collecting interned
values. However, this comes at the cost that queries now track which
interned values they created (or read). The micro benchmarks in the
salsa repo showed a significant perf regression. Will see if this also
visible in our benchmarks.

## Test Plan

`cargo test`
2025-03-17 11:05:54 +01:00
Micha Reiser
a467e7c8d3
[red-knot] Case sensitive module resolver (#16521)
## Summary

This PR implements the first part of
https://github.com/astral-sh/ruff/discussions/16440. It ensures that Red
Knot's module resolver is case sensitive on all systems.

This PR combines a few approaches:

1. It uses `canonicalize` on non-case-sensitive systems to get the real
casing of a path. This works for as long as no symlinks or mapped
network drives (the windows `E:\` is mapped to `\\server\share` thingy).
This is the same as what Pyright does
2. If 1. fails, fall back to recursively list the parent directory and
test if the path's file name matches the casing exactly as listed in by
list dir. This is the same approach as CPython takes in its module
resolver. The main downside is that it requires more syscalls because,
unlike CPython, we Red Knot needs to invalidate its caches if a file
name gets renamed (CPython assumes that the folders are immutable).

It's worth noting that the file watching test that I added that renames
`lib.py` to `Lib.py` currently doesn't pass on case-insensitive systems.
Making it pass requires some more involved changes to `Files`. I plan to
work on this next. There's the argument that landing this PR on its own
isn't worth it without this issue being addressed. I think it's still a
good step in the right direction even when some of the details on how
and where the path case sensitive comparison is implemented.

## Test plan

I added multiple integration tests (including a failing one). I tested
that the `case-sensitivity` detection works as expected on Windows,
MacOS and Linux and that the fast-paths are taken accordingly.
2025-03-14 19:16:44 +00:00
Micha Reiser
ce0018c3cb
Add OsSystem support to mdtests (#16518)
## Summary

This PR introduces a new mdtest option `system` that can either be
`in-memory` or `os`
where `in-memory` is the default.

The motivation for supporting `os` is so that we can write OS/system
specific tests
with mdtests. Specifically, I want to write mdtests for the module
resolver,
testing that module resolution is case sensitive. 

## Test Plan

I tested that the case-sensitive module resolver test start failing when
setting `system = "os"`
2025-03-06 10:41:40 +01:00
Micha Reiser
4732c58829
Rename venv-path to python (#16347) 2025-02-24 19:41:06 +01:00
Brent Westbrook
a9efdea113
Use ast::PythonVersion internally in the formatter and linter (#16170)
## Summary

This PR updates the formatter and linter to use the `PythonVersion`
struct from the `ruff_python_ast` crate internally. While this doesn't
remove the need for the `linter::PythonVersion` enum, it does remove the
`formatter::PythonVersion` enum and limits the use in the linter to
deserializing from CLI arguments and config files and moves most of the
remaining methods to the `ast::PythonVersion` struct.

## Test Plan

Existing tests, with some inputs and outputs updated to reflect the new
(de)serialization format. I think these are test-specific and shouldn't
affect any external (de)serialization.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-02-18 12:03:13 -05:00
Brent Westbrook
f58a54f043
Move red_knot_python_semantic::PythonVersion to the ruff_python_ast crate (#16147)
## Summary

This PR moves the `PythonVersion` struct from the
`red_knot_python_semantic` crate to the `ruff_python_ast` crate so that
it can be used more easily in the syntax error detection work. Compared
to that [prototype](https://github.com/astral-sh/ruff/pull/16090/) these
changes reduce us from 2 `PythonVersion` structs to 1.

This does not unify any of the `PythonVersion` *enums*, but I hope to
make some progress on that in a follow-up.

## Test Plan

Existing tests, this should not change any external behavior.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-02-14 12:48:08 -05:00
Ibraheem Ahmed
69d86d1d69
Transition to salsa coarse-grained tracked structs (#15763)
## Summary

Transition to using coarse-grained tracked structs (depends on
https://github.com/salsa-rs/salsa/pull/657). For now, this PR doesn't
add any `#[tracked]` fields, meaning that any changes cause the entire
struct to be invalidated. It also changes `AstNodeRef` to be
compared/hashed by pointer address, instead of performing a deep AST
comparison.

## Test Plan

This yields a 10-15% improvement on my machine (though weirdly some runs
were 5-10% without being flagged as inconsistent by criterion, is there
some non-determinism involved?). It's possible that some of this is
unrelated, I'll try applying the patch to the current salsa version to
make sure.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2025-02-11 11:38:50 +01:00
David Peter
7855f03735
[red-knot] Support custom typeshed Markdown tests (#15683)
## Summary

- Add feature to specify a custom typeshed from within Markdown-based
  tests
- Port "builtins" unit tests from `infer.rs` to Markdown tests, part of
  #13696

## Test Plan

- Tests for the custom typeshed feature
- New Markdown tests for deleted Rust unit tests
2025-01-23 12:36:38 +01:00
Micha Reiser
067c6de465
Change EnvironmentOptions::venv-path to Option<SystemPathBuf> (#15631)
## Summary

The `Options` struct is intended to capture the user's configuration
options but
`EnvironmentOptions::venv_path` supports both a `SitePackages::Known`
and `SitePackages::Derived`.

Users should only be able to provide `SitePackages::Derived`—they
specify a path to a venv, and Red Knot derives the path to the
site-packages directory. We'll only use the `Known` variant once we
automatically discover the Python installation.

That's why this PR changes `EnvironmentOptions::venv_path` from
`Option<SitePackages>` to `Option<SystemPathBuf>`.

This requires making some changes to the file watcher test, and I
decided to use `extra_paths` over venv path
because our venv validation is annoyingly correct -- making mocking a
venv rather involved.

## Test Plan

`cargo test`
2025-01-21 14:10:41 +00:00
Micha Reiser
eb47a6634d
Add support for configuring knot in pyproject.toml files (#15493)
## Summary

This PR adds support for configuring Red Knot in the `tool.knot` section
of the project's
`pyproject.toml` section. Options specified on the CLI precede the
options in the configuration file.

This PR only supports the `environment` and the `src.root` options for
now.
Other options will be added as separate PRs.

There are also a few concerns that I intentionally ignored as part of
this PR:

* Handling of relative paths: We need to anchor paths relative to the
current working directory (CLI), or the project (`pyproject.toml` or
`knot.toml`)
* Tracking the source of a value. Diagnostics would benefit from knowing
from which configuration a value comes so that we can point the user to
the right configuration file (or CLI) if the configuration is invalid.
* Schema generation and there's a lot more; see
https://github.com/astral-sh/ruff/issues/15491

This PR changes the default for first party codes: Our existing default
was to only add the project root. Now, Red Knot adds the project root
and `src` (if such a directory exists).

Theoretically, we'd have to add a file watcher event that changes the
first-party search paths if a user later creates a `src` directory. I
think this is pretty uncommon, which is why I ignored the complexity for
now but I can be persuaded to handle it if it's considered important.

Part of https://github.com/astral-sh/ruff/issues/15491

## Test Plan

Existing tests, new file watching test demonstrating that changing the
python version and platform is correctly reflected.
2025-01-17 09:41:06 +01:00
Micha Reiser
18d5dbfb7f
Remove workspace support (#15472) 2025-01-15 09:03:38 +01:00
David Peter
000948ad3b
[red-knot] Statically known branches (#15019)
## Summary

This changeset adds support for precise type-inference and
boundness-handling of definitions inside control-flow branches with
statically-known conditions, i.e. test-expressions whose truthiness we
can unambiguously infer as *always false* or *always true*.

This branch also includes:
- `sys.platform` support
- statically-known branches handling for Boolean expressions and while
  loops
- new `target-version` requirements in some Markdown tests which were
  now required due to the understanding of `sys.version_info` branches.

closes #12700 
closes #15034 

## Performance

### `tomllib`, -7%, needs to resolve one additional module (sys)

| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|:---|---:|---:|---:|---:|
| `./red_knot_main --project /home/shark/tomllib` | 22.2 ± 1.3 | 19.1 |
25.6 | 1.00 |
| `./red_knot_feature --project /home/shark/tomllib` | 23.8 ± 1.6 | 20.8
| 28.6 | 1.07 ± 0.09 |

### `black`, -6%

| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|:---|---:|---:|---:|---:|
| `./red_knot_main --project /home/shark/black` | 129.3 ± 5.1 | 119.0 |
137.8 | 1.00 |
| `./red_knot_feature --project /home/shark/black` | 136.5 ± 6.8 | 123.8
| 147.5 | 1.06 ± 0.07 |

## Test Plan

- New Markdown tests for the main feature in
  `statically-known-branches.md`
- New Markdown tests for `sys.platform`
- Adapted tests for `EllipsisType`, `Never`, etc
2024-12-21 11:33:10 +01:00
Micha Reiser
dcb99cc817
Fix stale File status in tests (#15030)
## Summary

Fixes https://github.com/astral-sh/ruff/issues/15027

The `MemoryFileSystem::write_file` API automatically creates
non-existing ancestor directoryes
but we failed to update the status of the now created ancestor
directories in the `Files` data structure.


## Test Plan

Tested that the case in https://github.com/astral-sh/ruff/issues/15027
now passes regardless of whether the *Simple* case is commented out or
not
2024-12-17 12:45:36 +01:00
Micha Reiser
c1837e4189
Rename custom-typeshed-dir, target-version and current-directory CLI options (#14930)
## Summary

This PR renames the `--custom-typeshed-dir`, `target-version`, and
`--current-directory` cli options to `--typeshed`,
`--python-version`, and `--project` as discussed in the CLI proposal
document.
I added aliases for `--target-version` (for Ruff compat) and
`--custom-typeshed-dir` (for Alex)

## Test Plan

Long help

```
An extremely fast Python type checker.

Usage: red_knot [OPTIONS] [COMMAND]

Commands:
  server  Start the language server
  help    Print this message or the help of the given subcommand(s)

Options:
      --project <PROJECT>
          Run the command within the given project directory.
          
          All `pyproject.toml` files will be discovered by walking up the directory tree from the project root, as will the project's virtual environment (`.venv`).
          
          Other command-line arguments (such as relative paths) will be resolved relative to the current working directory."#,

      --venv-path <PATH>
          Path to the virtual environment the project uses.
          
          If provided, red-knot will use the `site-packages` directory of this virtual environment to resolve type information for the project's third-party dependencies.

      --typeshed-path <PATH>
          Custom directory to use for stdlib typeshed stubs

      --extra-search-path <PATH>
          Additional path to use as a module-resolution source (can be passed multiple times)

      --python-version <VERSION>
          Python version to assume when resolving types
          
          [possible values: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13]

  -v, --verbose...
          Use verbose output (or `-vv` and `-vvv` for more verbose output)

  -W, --watch
          Run in watch mode by re-running whenever files change

  -h, --help
          Print help (see a summary with '-h')

  -V, --version
          Print version
```

Short help 

```
An extremely fast Python type checker.

Usage: red_knot [OPTIONS] [COMMAND]

Commands:
  server  Start the language server
  help    Print this message or the help of the given subcommand(s)

Options:
      --project <PROJECT>         Run the command within the given project directory
      --venv-path <PATH>          Path to the virtual environment the project uses
      --typeshed-path <PATH>      Custom directory to use for stdlib typeshed stubs
      --extra-search-path <PATH>  Additional path to use as a module-resolution source (can be passed multiple times)
      --python-version <VERSION>  Python version to assume when resolving types [possible values: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13]
  -v, --verbose...                Use verbose output (or `-vv` and `-vvv` for more verbose output)
  -W, --watch                     Run in watch mode by re-running whenever files change
  -h, --help                      Print help (see more with '--help')
  -V, --version                   Print version

```

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-12-13 08:21:52 +00:00
Micha Reiser
b63c2e126b
Upgrade Rust toolchain to 1.83 (#14677) 2024-11-29 12:05:05 +00:00
Micha Reiser
32b57b2ee4
Enable nursery rules: 'redundant_clone', 'debug_assert_with_mut_call', and 'unused_peekable' (#13920) 2024-10-25 09:46:30 +02:00
Micha Reiser
5f65e842e8
Upgrade salsa (#13757) 2024-10-15 11:06:32 +00:00
Charlie Marsh
c3b40da0d2
Use backticks for code in red-knot messages (#13599)
## Summary

...and remove periods from messages that don't span more than a single
sentence.

This is more consistent with how we present user-facing messages in uv
(which has a defined style guide).
2024-10-02 03:14:28 +00:00
Micha Reiser
8921fbb54c
vendored_typeshed_versions should use db.vendored (#13434) 2024-09-21 16:35:06 +02:00
Simon
594dee1b0b
[red-knot] resolve source/stubs over namespace packages (#13254) 2024-09-06 12:14:26 +01:00
Micha Reiser
dce87c21fd
Eagerly validate typeshed versions (#12786) 2024-08-21 15:49:53 +00:00
Alex Waygood
37a60460ed
[red-knot] Improve various tracing logs (#13015) 2024-08-20 18:34:51 +00:00
Micha Reiser
a99a45868c
Eagerly validate search paths (#12783)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-08-12 07:46:59 +00:00
Alex Waygood
cf1a57df5a
Remove red_knot_python_semantic::python_version::TargetVersion (#12790) 2024-08-10 14:28:31 +01:00
Alex Waygood
37b9bac403
[red-knot] Add support for --system-site-packages virtual environments (#12759) 2024-08-09 21:02:16 +01:00
Alex Waygood
c4e651921b
[red-knot] Move, rename and make public the PyVersion type (#12782) 2024-08-09 16:49:17 +01:00
Micha Reiser
a176679b24
Log warnings when skipping editable installations (#12779) 2024-08-09 16:29:43 +02:00
Micha Reiser
2abfab0f9b
Move Program and related structs to red_knot_python_semantic (#12777) 2024-08-09 11:50:45 +02:00
Alex Waygood
f1de08c2a0
[red-knot] Merge the semantic and module-resolver crates (#12751) 2024-08-08 15:34:11 +01:00
Renamed from crates/red_knot_module_resolver/src/resolver.rs (Browse further)