114 Commits
Author SHA1 Message Date
astral-automations-bot[bot]andBrent Westbrook ba65abf8ba Bump version to 0.17.3 (#29745)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-10-26 20:14:27 -04:00
astral-automations-bot[bot]andBrent Westbrook 30516b42ab Bump version to 0.17.2 (#29637)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-10-22 13:54:24 -04:00
astral-automations-bot[bot] 4683270c69 Bump version to 0.17.1 (#29420)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
2026-10-15 10:56:41 -04:00
astral-automations-bot[bot]andBrent Westbrook 5b27c1ccfa Bump version to 0.17.0 (#29259)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2026-10-09 13:45:29 -04:00
astral-automations-bot[bot]andBrent Westbrook 3265ed1f94 Bump version to 0.16.10 (#29055)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2026-10-01 13:40:09 -04:00
astral-automations-bot[bot]andBrent Westbrook 0be08a206f Bump version to 0.16.9 (#28882)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-09-24 16:21:50 -04:00
astral-automations-bot[bot]andBrent Westbrook 62914c4b9b Bump version to 0.16.8 (#28648)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-09-16 11:31:02 -04:00
Charlie Marsh e0a77db7b7 Add accessors for comparison expressions (#28485)
## Summary

We add accessors and iteration methods to `ExprCompare` and use them
throughout AST visitors, formatting, lint rules, and type inference. For
`a < b <= c`, `iter` yields `(a, Lt, b)` and `(b, LtE, c)`. `as_single`
returns a triple only when there is exactly one operator and two
operands, so callers can match an operator and both operands together
while rejecting comparison chains. Rules that only inspect operands use
the existing operand slice directly.

The `first_operand`, `first_operator`, and `second_operand` accessors
assert the parser's existing guarantee that a comparison has at least
one operator and two operands. Error recovery synthesizes missing
operands; manually constructed ASTs must uphold the same invariant.
2026-09-10 15:55:08 -04:00
Charlie Marsh 7b13f01ba1 [ty] Reduce retained AST memory by shrinking expressions (#28335)
## Summary

We reduce `Expr` from 64 to 56 bytes on 64-bit targets. The largest
variants determine the enum's size, so shrinking those variants saves
eight bytes in every `Expr` value, including expressions in the parsed
modules retained by ty.

The changes are:

- Store positional call arguments in `ThinVec`, reducing `Arguments` and
`ExprCall` by eight bytes.
- Store all comparison operands in one boxed slice. This removes the
separate left-operand allocation and reduces `ExprCompare` by eight
bytes while keeping operators in a boxed slice.
- Store dictionary-comprehension generators in a boxed slice, reducing
`ExprDictComp` by eight bytes.
- Store f-string and t-string elements in boxed slices, and represent a
single f-string directly as `FString`. This keeps single parts inline
and reduces `ExprFString` and `ExprTString` by eight bytes.

The parser, AST visitors, formatter, lint rules, and type inference use
the updated layouts. Size assertions cover the 56-byte enum and its
affected variants.
2026-09-10 15:39:14 -04:00
astral-automations-bot[bot]andBrent Westbrook b5dba861cc Bump version to 0.16.7 (#28496)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-09-10 13:47:30 -04:00
Alex Waygood 71b790029c [ty] Move ty_ide's importer to ty_python_semantic (#28170)
Future autofixes will need to introduce imports alongside code changes.
In particular, there are cases where inserting `assert_never(...)` would
be useful, but the fix often also needs to import `assert_never`. The
importer currently lives in `ty_ide`, so diagnostics emitted by
`ty_python_semantic` cannot use it.

Move the importer into `ty_python_semantic` and reuse it from
completions and inlay hints. As its first use in a diagnostic, attach
the `reveal_type` import fix directly to `undefined-reveal`, replacing
the custom LSP handling. The fix imports from `typing` on Python 3.11+
and `typing_extensions` on older Python versions.

Cache source-style detection and top-level import discovery in Salsa per
file, so diagnostics in separate inference regions and IDE features can
share the setup. The cached data does not retain the parsed AST or a
copy of the source text.

Stacked on #28169.
2026-09-06 00:29:01 +01:00
Brent Westbrook 22f65a2ab5 Bump 0.16.6 (#28280) 2026-09-03 12:36:42 -04:00
Brent Westbrook 9e4938c4a6 Bump 0.16.5 (#28110) 2026-08-27 12:09:07 -04:00
Brent Westbrook 11c76bf48f Bump 0.16.4 (#27937) 2026-08-20 13:14:29 -04:00
Brent Westbrook b0e47022cf Bump 0.16.3 (#27723) 2026-08-13 09:39:16 -04:00
Charlie MarshandCharlie Marsh c56aad17fd [ty] Reduce Expr size to 64 bytes (#27591)
## Summary

This PR reduces the size of `Expr` from 72 to 64 bytes by storing only
the start offset on `ExprCall` (64 to 56 bytes) and boxing the uncommon
implicitly concatenated string representation in `ExprStringLiteral` (64
to 48 bytes). Both changes are required to reduce the size of the
containing `Expr` enum.

`ExprCall` derives its end offset from its argument list; parser and
error-recovery paths assert that their ranges share the same end.

---------

Co-authored-by: Charlie Marsh <charliemarsh@openai.com>
2026-08-09 13:41:24 +00:00
Brent Westbrook 5b48a04097 Bump 0.16.2 (#27555) 2026-08-07 09:12:50 -04:00
Charlie Marsh 6cfeb8aa07 Narrow internal visibility with Hawk (#27339)
## Summary

This PR uses Hawk 0.1.11 to narrow internal declarations to the
visibility they actually need.

Here, I've intentionally _only_ made visibility changes; unused API
removals are split into follow-up PRs. In total, 1,201 declaration
visibility modifiers are narrowed. Public generated formatter APIs and
other declarations whose narrower visibility would activate dead-code or
API-shape lints remain unchanged.
2026-07-31 22:08:13 -04:00
Brent Westbrook 80790b348b Bump 0.16.1 (#27330) 2026-07-30 13:54:42 -04:00
Brent Westbrook a2635fd8f3 Bump 0.16.0 (#27136) 2026-07-23 14:37:34 -04:00
Brent Westbrook 0177a7e0d2 Bump 0.15.22 (#26884) 2026-07-16 10:54:43 -04:00
Brent Westbrook 3e1f636451 Bump 0.15.21 (#26676) 2026-07-09 15:42:27 -04:00
Brent Westbrook f82a36b6ba Bump 0.15.20 (#26376) 2026-06-25 10:00:55 -07:00
Charlie Marsh 7f0436561d Bump version to 0.15.19 (#26291) 2026-06-23 20:42:26 -04:00
Charlie Marsh dff016b7a4 Publish Ruff crates to crates.io (#26271)
## Summary

Publish Ruff's production Rust crates to crates.io as part of the
existing release workflow. This follows uv's setup: workspace
dependencies carry registry-compatible version pins, internal crates
receive generated READMEs and an explicit versioning policy, CI dry-runs
the full workspace publish, and release jobs publish missing crate
versions idempotently through crates.io trusted publishing.

The publishing set contains 32 packages: Ruff's CLI, WASM package,
server, linter, formatter, parser, and the internal Ruff component
crates required by them. It also includes `ty_module_resolver`,
`ty_site_packages`, and `ty_static`, because those three crates are part
of Ruff's normal dependency closure.

The publishing set deliberately excludes:

- Test-only crates: `mdtest`, `ruff_mdtest`,
`ruff_python_ast_integration_tests`, and
`ruff_python_trivia_integration_tests`.
- Benchmark and development crates: `ruff_benchmark` and `ruff_dev`.
- All remaining `ty_*` crates.

These packages retain `publish = false`, so bootstrap, version bumping,
README generation, CI dry-runs, and release publishing skip them through
Cargo metadata instead of a separate hard-coded allowlist.

The crates.io job is intentionally independent of release announcement,
so a crates.io outage cannot block the existing binary, PyPI, npm, or
GitHub release outputs. A bootstrap script reserves new crate names,
configures the release workflow as each crate's trusted publisher,
enables trusted-publishing-only releases, and records configured crates
for idempotent reruns.

The full workspace publish dry-run packages and verifies all 32 selected
crates.

Closes https://github.com/astral-sh/ruff/issues/43.
2026-06-23 12:49:23 -04:00
Jelle Zijlstra 409c13f3ec Add full PEP 798 support (#25104)
Fixes #25098.

This adds full support for PEP 798 through the parser, linter,
formatter, and type checker.
There are a lot of changes but they are mostly straightforward. Let me
know though if it's better to split this up.
2026-05-16 16:32:57 +01:00
Eyüp Can AkmanandMicha Reiser f32733c063 [flake8-pyi] Fix PYI016 false positive for f-string debug specifier (#24098)
Co-authored-by: Micha Reiser <micha@reiser.io>
2026-04-30 11:14:25 +02:00
Micha Reiser 24083af5a9 Rename patterns and arguments source order iterator method (#24532) 2026-04-10 07:32:15 +00:00
Shunsuke Shibayama ce2cb82b0f Run end-of-file-fixer pre-commit hook on ty corpus test files (#23908) 2026-03-12 11:41:56 +00:00
Alex Waygood 0d84a0654a [ty] Add validation for type parameters with defaults after TypeVarTuple (#23807) 2026-03-08 18:28:16 +00:00
Charlie Marsh 8a10b6743c Add support for lazy import parsing (#23755)
## Summary

This PR adds `is_lazy` to the AST and parser, and supports `lazy` import
formatting in the formatter. The name `is_lazy` matches the [CPython
AST](https://github.com/python/cpython/blob/c3fb0d9d96902774c08b199dda0479a8d31398a5/Parser/Python.asdl#L48),
though we could modify it if there's demand.

There are no further changes to Ruff rules or even to Ruff import
sorting, since those deserve separate design discussions.

I've also omitted support for flagging semantic syntax errors (e.g.,
`lazy import` inside `def`).

See: https://github.com/astral-sh/ruff/issues/21305.
2026-03-06 09:12:21 -05:00
Micha Reiser d08e414179 Update MSRV to 1.90 (#21987) 2025-12-15 14:29:11 +01:00
Micha Reiser 515de2d062 Move Token, TokenKind and Tokens to ruff-python-ast (#21760) 2025-12-02 20:10:46 +01:00
Shahar NavehandMicha Reiser a2d0d39853 Configurable "unparse mode" for ruff_python_codegen::Generator (#21041)
Co-authored-by: Micha Reiser <micha@reiser.io>
2025-10-24 15:44:48 +00:00
Shahar Naveh 48ada2d359 Generator preferred quote style (#20434) 2025-09-18 12:57:21 +02:00
Andrew Gallant a47a50e6e2 [ruff] Provide a way to get an owned Stylist
This makes it easier to test with in some cases and generally shouldn't
cost anything.
2025-09-17 13:59:28 -04:00
Shahar Naveh cb1ba0d4c2 Expose Indentation in ruff_python_codegen (#20216)
## Summary

I'm trying to reduce code complexity for
[RustPython](https://github.com/RustPython/RustPython), we have this
file:
https://github.com/RustPython/RustPython/blob/056795eed4dc0b09de00c2fabe45493ea1de7194/compiler/codegen/src/unparse.rs
which can be replaced entirely by `ruff_python_codegen::Generator`.
Unfortunately we can not create an instance of `Generator` easily,
because `Indentation` is not exported at
https://github.com/astral-sh/ruff/blob/cda376afe079b54b6779704bdd740c9e81423e39/crates/ruff_python_codegen/src/lib.rs#L3

I have managed to bypass this restriction by doing:
```rust
let contents = r"x = 1";
let module = ruff_python_parser::parse_module(contents).unwrap();
let stylist = ruff_python_codegen::Stylist::from_tokens(module.tokens(), contents);
stylist.indentation()
```

But ideally I'd rather use:
```rust
ruff_python_codegen::Indentation::default()
```
2025-09-03 13:32:31 -04:00
Micha Reiser 7dfde3b929 Update Rust toolchain to 1.89 (#19807) 2025-08-07 18:21:50 +02:00
Dylan 008bbfdf5a Disallow implicit concatenation of t-strings and other string types (#19485)
As of [this cpython PR](https://github.com/python/cpython/pull/135996),
it is not allowed to concatenate t-strings with non-t-strings,
implicitly or explicitly. Expressions such as `"foo" t"{bar}"` are now
syntax errors.

This PR updates some AST nodes and parsing to reflect this change.

The structural change is that `TStringPart` is no longer needed, since,
as in the case of `BytesStringLiteral`, the only possibilities are that
we have a single `TString` or a vector of such (representing an implicit
concatenation of t-strings). This removes a level of nesting from many
AST expressions (which is what all the snapshot changes reflect), and
simplifies some logic in the implementation of visitors, for example.

The other change of note is in the parser. When we meet an implicit
concatenation of string-like literals, we now count the number of
t-string literals. If these do not exhaust the total number of
implicitly concatenated pieces, then we emit a syntax error. To recover
from this syntax error, we encode any t-string pieces as _invalid_
string literals (which means we flag them as invalid, record their
range, and record the value as `""`). Note that if at least one of the
pieces is an f-string we prefer to parse the entire string as an
f-string; otherwise we parse it as a string.

This logic is exactly the same as how we currently treat
`BytesStringLiteral` parsing and error recovery - and carries with it
the same pros and cons.

Finally, note that I have not implemented any changes in the
implementation of the formatter. As far as I can tell, none are needed.
I did change a few of the fixtures so that we are always concatenating
t-strings with t-strings.
2025-07-27 12:41:03 +00:00
GiGaGon d2684a00c6 Fix f-string interpolation escaping (#18882) 2025-06-25 10:04:15 +02:00
Ibraheem Ahmed c9dff5c7d5 [ty] AST garbage collection (#18482)
## Summary

Garbage collect ASTs once we are done checking a given file. Queries
with a cross-file dependency on the AST will reparse the file on demand.
This reduces ty's peak memory usage by ~20-30%.

The primary change of this PR is adding a `node_index` field to every
AST node, that is assigned by the parser. `ParsedModule` can use this to
create a flat index of AST nodes any time the file is parsed (or
reparsed). This allows `AstNodeRef` to simply index into the current
instance of the `ParsedModule`, instead of storing a pointer directly.

The indices are somewhat hackily (using an atomic integer) assigned by
the `parsed_module` query instead of by the parser directly. Assigning
the indices in source-order in the (recursive) parser turns out to be
difficult, and collecting the nodes during semantic indexing is
impossible as `SemanticIndex` does not hold onto a specific
`ParsedModuleRef`, which the pointers in the flat AST are tied to. This
means that we have to do an extra AST traversal to assign and collect
the nodes into a flat index, but the small performance impact (~3% on
cold runs) seems worth it for the memory savings.

Part of https://github.com/astral-sh/ty/issues/214.
2025-06-13 08:40:11 -04:00
Dylan 9bbf4987e8 Implement template strings (#17851)
This PR implements template strings (t-strings) in the parser and
formatter for Ruff.

Minimal changes necessary to compile were made in other parts of the code (e.g. ty, the linter, etc.). These will be covered properly in follow-up PRs.
2025-05-30 15:00:56 -05:00
Micha Reiser 9ae698fe30 Switch to Rust 2024 edition (#18129) 2025-05-16 13:25:28 +02:00
Micha Reiser fa628018b2 Use #[expect(lint)] over #[allow(lint)] where possible (#17822) 2025-05-03 21:20:31 +02:00
Micha ReiserandAlex Waygood 8a4158c5f8 Upgrade to Rust 1.86 and bump MSRV to 1.84 (#17171)
<!--
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

I decided to disable the new
[`needless_continue`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue)
rule because I often found the explicit `continue` more readable over an
empty block or having to invert the condition of an other branch.


## Test Plan

`cargo test`

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-04-03 15:59:44 +00:00
Brent Westbrook 97d0659ce3 Pass ParserOptions to the parser (#16220)
## Summary

This is part of the preparation for detecting syntax errors in the
parser from https://github.com/astral-sh/ruff/pull/16090/. As suggested
in [this
comment](https://github.com/astral-sh/ruff/pull/16090/#discussion_r1953084509),
I started working on a `ParseOptions` struct that could be stored in the
parser. For this initial refactor, I only made it hold the existing
`Mode` option, but for syntax errors, we will also need it to have a
`PythonVersion`. For that use case, I'm picturing something like a
`ParseOptions::with_python_version` method, so you can extend the
current calls to something like

```rust
ParseOptions::from(mode).with_python_version(settings.target_version)
```

But I thought it was worth adding `ParseOptions` alone without changing
any other behavior first.

Most of the diff is just updating call sites taking `Mode` to take
`ParseOptions::from(Mode)` or those taking `PySourceType`s to take
`ParseOptions::from(PySourceType)`. The interesting changes are in the
new `parser/options.rs` file and smaller parts of `parser/mod.rs` and
`ruff_python_parser/src/lib.rs`.

## Test Plan

Existing tests, this should not change any behavior.
2025-02-19 10:50:50 -05:00
Brent WestbrookandAlex Waygood b5e5271adf Preserve triple quotes and prefixes for strings (#15818)
## Summary

This is a follow-up to #15726, #15778, and #15794 to preserve the triple
quote and prefix flags in plain strings, bytestrings, and f-strings.

I also added a `StringLiteralFlags::without_triple_quotes` method to
avoid passing along triple quotes in rules like SIM905 where it might
not make sense, as discussed
[here](https://github.com/astral-sh/ruff/pull/15726#discussion_r1930532426).

## Test Plan

Existing tests, plus many new cases in the `generator::tests::quote`
test that should cover all combinations of quotes and prefixes, at least
for simple string bodies.

Closes #7799 when combined with #15694, #15726, #15778, and #15794.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-02-04 08:41:06 -05:00
Brent WestbrookandAlex Waygood 23c98849fc Preserve quotes in generated f-strings (#15794)
## Summary

This is another follow-up to #15726 and #15778, extending the
quote-preserving behavior to f-strings and deleting the now-unused
`Generator::quote` field.

## Details
I also made one unrelated change to `rules/flynt/helpers.rs` to remove a
`to_string` call for making a `Box<str>` and tweaked some arguments to
some of the `Generator::unparse_f_string` methods to make the code
easier to follow, in my opinion. Happy to revert especially the latter
of these if needed.

Unfortunately this still does not fix the issue in #9660, which appears
to be more of an escaping issue than a quote-preservation issue. After
#15726, the result is now `a = f'# {"".join([])}' if 1 else ""` instead
of `a = f"# {''.join([])}" if 1 else ""` (single quotes on the outside
now), but we still don't have the desired behavior of double quotes
everywhere on Python 3.12+. I added a test for this but split it off
into another branch since it ended up being unaddressed here, but my
`dbg!` statements showed the correct preferred quotes going into
[`UnicodeEscape::with_preferred_quote`](https://github.com/astral-sh/ruff/blob/main/crates/ruff_python_literal/src/escape.rs#L54).

## Test Plan

Existing rule and `Generator` tests.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-01-29 13:28:22 -05:00
Brent Westbrook 98d20a8219 Preserve quotes in generated byte strings (#15778)
## Summary

This is a very closely related follow-up to #15726, adding the same
quote-preserving behavior to bytestrings. Only one rule (UP018) was
affected this time, and it was easy to mirror the plain string changes.

## Test Plan

Existing tests
2025-01-28 08:19:40 -05:00
Brent WestbrookandAlex Waygood 9bf138c45a Preserve quote style in generated code (#15726)
## Summary

This is a first step toward fixing #7799 by using the quoting style
stored in the `flags` field on `ast::StringLiteral`s to select a quoting
style. This PR does not include support for f-strings or byte strings.

Several rules also needed small updates to pass along existing quoting
styles instead of using `StringLiteralFlags::default()`. The remaining
snapshot changes are intentional and should preserve the quotes from the
input strings.

## Test Plan

Existing tests with some accepted updates, plus a few new RUF055 tests
for raw strings.

---------

Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2025-01-27 13:41:03 -05:00