Compare commits

..

113 Commits

Author SHA1 Message Date
Dhruv Manilawala
91c712cdb1 Use Invalid context when keyword used as identifier 2024-12-03 16:53:40 +05:30
InSync
246a6df87d [red-knot] Deeper understanding of LiteralString (#14649)
## Summary

Resolves #14648.

## Test Plan

Markdown tests.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2024-12-03 03:31:58 +00:00
Connor Skees
3e702e12f7 red-knot: support narrowing for bool(E) (#14668)
Resolves https://github.com/astral-sh/ruff/issues/14547 by delegating
narrowing to `E` for `bool(E)` where `E` is some expression.

This change does not include other builtin class constructors which
should also work in this position, like `int(..)` or `float(..)`, as the
original issue does not mention these. It should be easy enough to add
checks for these as well if we want to.

I don't see a lot of markdown tests for malformed input, maybe there's a
better place for the no args and too many args cases to go?

I did see after the fact that it looks like this task was intended for a
new hire.. my apologies. I got here from
https://github.com/astral-sh/ruff/issues/13694, which is marked
help-wanted.

---------

Co-authored-by: David Peter <mail@david-peter.de>
2024-12-03 03:04:59 +00:00
Dylan
91e2d9a139 [refurb] Handle non-finite decimals in verbose-decimal-constructor (FURB157) (#14596)
This PR extends the Decimal parsing used in [verbose-decimal-constructor
(FURB157)](https://docs.astral.sh/ruff/rules/verbose-decimal-constructor/)
to better handle non-finite `Decimal` objects, avoiding some false
negatives.

Closes #14587

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2024-12-02 18:13:20 -06:00
David Peter
5137fcc9c8 [red-knot] Re-enable linter corpus tests (#14736)
## Summary

Seeing the fuzzing results from @dhruvmanila in #13778, I think we can
re-enable these tests. We also had one regression that would have been
caught by these tests, so there is some value in having them enabled.
2024-12-02 20:11:30 +01:00
Matt Ord
83651deac7 [pylint] Ignore overload in PLR0904 (#14730)
Fixes #14727

## Summary

Fixes #14727

## Test Plan

cargo test

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2024-12-02 14:36:51 +00:00
Alex Waygood
6dfe125f44 Improve error messages and docs for flake8-comprehensions rules (#14729) 2024-12-02 13:36:15 +00:00
Micha Reiser
f96dfc179f Revert: [pyflakes] Avoid false positives in @no_type_check contexts (F821, F722) (#14615) (#14726) 2024-12-02 14:28:27 +01:00
Tzu-ping Chung
76d2e56501 [airflow] Avoid deprecated values (AIR302) (#14582) 2024-12-02 07:39:26 +00:00
Micha Reiser
30d80d9746 Sort discovered workspace packages for consistent cross-platform package discovery (#14725) 2024-12-02 07:36:08 +00:00
renovate[bot]
5a67d3269b Update pre-commit dependencies (#14719) 2024-12-02 06:02:56 +00:00
renovate[bot]
02d1e6a94a Update dawidd6/action-download-artifact action to v7 (#14722) 2024-12-02 01:25:51 +00:00
Simon Brugman
48ec3a8add [refurb] Guard hashlib imports and mark hashlib-digest-hex fix as safe (FURB181) (#14694)
## Summary

- Check if `hashlib` and `crypt` imports have been seen for `FURB181`
and `S324`
- Mark the fix for `FURB181` as safe: I think it was accidentally marked
as unsafe in the first place. The rule does not support user-defined
classes as the "fix safety" section suggests.
- Removed `hashlib._Hash`, as it's not part of the `hashlib` module.

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

Updated the test snapshots
2024-12-01 20:24:49 -05:00
renovate[bot]
289a938ae8 Update astral-sh/setup-uv action to v4 (#14721) 2024-12-02 01:24:22 +00:00
renovate[bot]
3e5ab6cf38 Update NPM Development dependencies (#14720) 2024-12-02 01:24:09 +00:00
renovate[bot]
48d33595b9 Update dependency tomli to v2.2.1 (#14718) 2024-12-02 01:22:18 +00:00
renovate[bot]
23ee7a954e Update cloudflare/wrangler-action action to v3.13.0 (#14716) 2024-12-02 01:18:43 +00:00
renovate[bot]
d4a7c098dc Update Rust crate ureq to v2.11.0 (#14715) 2024-12-02 01:17:31 +00:00
renovate[bot]
0c5f03a059 Update dependency ruff to v0.8.1 (#14717) 2024-12-02 01:13:13 +00:00
renovate[bot]
239bfb6de7 Update Rust crate similar to v2.6.0 (#14714) 2024-12-01 20:04:07 -05:00
renovate[bot]
3c3ec6755c Update Rust crate rustc-hash to v2.1.0 (#14713) 2024-12-01 20:04:00 -05:00
renovate[bot]
4c05f2c8b4 Update tokio-tracing monorepo (#14710) 2024-12-01 20:03:50 -05:00
renovate[bot]
d594796e3a Update rust-wasm-bindgen monorepo (#14709) 2024-12-01 20:03:43 -05:00
renovate[bot]
b5ef2844ef Update Rust crate syn to v2.0.90 (#14708) 2024-12-01 20:03:36 -05:00
renovate[bot]
06183bd8a1 Update Rust crate pathdiff to v0.2.3 (#14707) 2024-12-01 20:03:29 -05:00
renovate[bot]
4068006c5f Update Rust crate libc to v0.2.167 (#14705) 2024-12-01 20:03:23 -05:00
renovate[bot]
145c97c94f Update Rust crate ordermap to v0.5.4 (#14706) 2024-12-01 20:03:05 -05:00
github-actions[bot]
84748be163 Sync vendored typeshed stubs (#14696)
Close and reopen this PR to trigger CI

Co-authored-by: typeshedbot <>
2024-12-01 01:38:31 +00:00
Brent Westbrook
9e017634cb [pep8-naming] Avoid false positive for class Bar(type(foo)) (N804) (#14683) 2024-11-30 22:37:28 +00:00
Simon Brugman
56ae73a925 [pylint] Fix false negatives for ascii and sorted in len-as-condition (PLC1802) (#14692) 2024-11-30 14:10:30 -06:00
InSync
be07424e80 Increase rule set size (#14689) 2024-11-30 15:12:10 +01:00
Connor Skees
579ef01294 mdtest: include test name in printed rerun command (#14684)
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-11-30 11:01:06 +00:00
Micha Reiser
90487b8cbd Skip panda rules if panda module hasn't been seen (#14671) 2024-11-29 21:32:51 +00:00
Alex Waygood
f3d8c023d3 [ruff] Avoid emitting assignment-in-assert when all references to the assigned variable are themselves inside asserts (RUF018) (#14661) 2024-11-29 13:36:59 +00:00
Micha Reiser
b63c2e126b Upgrade Rust toolchain to 1.83 (#14677) 2024-11-29 12:05:05 +00:00
Connor Skees
a6402fb51e mdtest: allow specifying a specific test inside a file (#14670) 2024-11-29 12:59:07 +01:00
Dhruv Manilawala
b3b2c982cd Update CHANGELOG.md with the new commits for 0.8.1 (#14664)
The 0.8.1 release was delayed, so this PR updates the CHANGELOG.md with
the latest commits on `main`.
2024-11-29 03:15:36 +00:00
Simon Brugman
abb3c6ea95 [flake8-pyi] Avoid rewriting invalid type expressions in unnecessary-type-union (PYI055) (#14660) 2024-11-28 18:30:50 +00:00
Brent Westbrook
224fe75a76 [ruff] Implement unnecessary-regular-expression (RUF055) (#14659)
Co-authored-by: Micha Reiser <micha@reiser.io>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Simon Brugman <sbrugman@users.noreply.github.com>
2024-11-28 18:29:23 +00:00
Simon Brugman
dc29f52750 [flake8-pyi, ruff] Fix traversal of nested literals and unions (PYI016, PYI051, PYI055, PYI062, RUF041) (#14641) 2024-11-28 18:07:12 +00:00
David Salvisberg
d9cbf2fe44 Avoids unnecessary overhead for TC004, when TC001-003 are disabled (#14657) 2024-11-28 16:28:24 +01:00
Samodya Abeysiriwardane
3f6c65e78c [red-knot] Fix merged type after if-else without explicit else branch (#14621)
## Summary

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

The final type of a variable after if-statement without explicit else
branch should be similar to having an explicit else branch.

## Test Plan

Originally failed test cases from the bug are added.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-11-28 06:23:55 -08:00
Dhruv Manilawala
976c37a849 Bump version to 0.8.1 (#14655) 2024-11-28 19:12:50 +05:30
David Peter
a378ff38dc [red-knot] Fix Boolean flags in mdtests (#14654)
## Summary

Similar to #14652, but now with conditions that are `Literal[True]`
(instead of `Literal[False]`), where we want them to be `bool`.
2024-11-28 14:29:35 +01:00
Alex Waygood
d8bca0d3a2 Fix bug where methods defined using lambdas were flagged by FURB118 (#14639) 2024-11-28 12:58:23 +00:00
David Peter
6f1cf5b686 [red-knot] Minor fix in MRO tests (#14652)
## Summary

`bool()` is equal to `False`, and we infer `Literal[False]` for it. Which
means that the test here will fail as soon as we treat the body of
this `if` as unreachable.
2024-11-28 10:17:15 +01:00
David Peter
8639f8c1a6 CI: Treat mdtest Markdown files as code (#14653)
## Summary

Make sure we run the tests for mdtest-only changes.

## Test Plan

Tested if positive glob patterns override negative patterns here:
https://codepen.io/mrmlnc/pen/OXQjMe
2024-11-28 10:04:20 +01:00
Alex Waygood
f1b2e85339 py-fuzzer: recommend using uvx rather than uv run to run the fuzzer (#14645) 2024-11-27 22:19:52 +00:00
David Salvisberg
6d61c8aa16 Fixes minor bug in SemanticModel::lookup_symbol (#14643)
## Summary

This came up as part of #12927 when implementing
`SemanticModel::simulate_runtime_load`.

Should be fairly self-explanatory, if the scope returns a binding with
`BindingKind::Annotation` the bottom part of the loop gets skipped, so
there's no chance for `seen_function` to have been updated. So unless
there's something subtle going on here, like function scopes never
containing bindings with `BindingKind::Annotation`, this seems like a
bug.

## Test Plan

`cargo nextest run`
2024-11-27 16:50:19 -05:00
David Salvisberg
8a7ba5d2df [flake8-type-checking] Fixes quote_type_expression (#14634) 2024-11-27 18:58:48 +01:00
Brent Westbrook
6fcbe8efb4 [ruff] Detect redirected-noqa in file-level comments (RUF101) (#14635) 2024-11-27 18:25:47 +01:00
Alexandra Valentine-Ketchum
c40b37aa36 N811 & N814: eliminate false positives for single-letter names (#14584)
Co-authored-by: Micha Reiser <micha@reiser.io>
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2024-11-27 14:38:36 +00:00
Alex Waygood
ef0e2a6e1b Refactor crates/ruff_python_stdlib/src/builtins.rs to make it easier to add support for new Python versions (#14632) 2024-11-27 12:20:21 +00:00
Alex Waygood
4fb1416bf4 Minor stylistic improvements for functions detecting PEP-604 unions (#14633) 2024-11-27 11:29:37 +00:00
Simon Brugman
8a860b89b4 Add social icons to the footer (#14591)
## Summary

Add social icons to the footer

`mkdocs-material` update is required for the `x-twitter` icon.

## Test Plan

Tested locally. 

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-11-27 11:07:45 +00:00
Dhruv Manilawala
f96fa6b0e2 Do not consider f-strings with escaped newlines as multiline (#14624)
## Summary

This PR fixes a bug in the f-string formatting to not consider the
escaped newlines for `is_multiline`. This is done by checking if the
f-string is triple-quoted or not similar to normal string literals.

This is not required to be gated behind preview because the logic change
for `is_multiline` was added in
https://github.com/astral-sh/ruff/pull/14454.

## Test Plan

Add a test case which formats differently on `main`:
https://play.ruff.rs/ea3c55c2-f0fe-474e-b6b8-e3365e0ede5e
2024-11-27 10:25:38 +00:00
Dhruv Manilawala
4cd2b9926e Gate is_multiline change behind preview (#14630)
## Summary

Ref:
https://github.com/astral-sh/ruff/pull/14624#pullrequestreview-2464127254

## Test Plan

The test case in the follow-up PR showcases the difference between
preview and non-preview formatting:
https://github.com/astral-sh/ruff/pull/14624/files#diff-dc25bd4df280d9a9180598075b5bc2d0bac30af956767b373561029309c8f024
2024-11-27 15:50:28 +05:30
Simon Brugman
11a2929ed7 [ruff] Implement unnecessary-nested-literal (RUF041) (#14323)
Co-authored-by: Micha Reiser <micha@reiser.io>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-11-27 10:01:50 +00:00
InSync
187974eff4 [flake8-use-pathlib] Recommend Path.iterdir() over os.listdir() (PTH208) (#14509)
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-11-27 09:53:13 +00:00
Micha Reiser
14ba469fc0 Use a derive macro for Violations (#14557)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-11-27 09:41:40 +00:00
David Salvisberg
6fd10e2fe7 [flake8-type-checking] Adds implementation for TC007 and TC008 (#12927)
Co-authored-by: Simon Brugman <sbrugman@users.noreply.github.com>
Co-authored-by: Carl Meyer <carl@oddbird.net>
2024-11-27 09:51:20 +01:00
Alex Waygood
e0f3eaf1dd Turn the fuzz-parser script into a properly packaged Python project (#14606)
## Summary

This PR gets rid of the `requirements.in` and `requirements.txt` files
in the `scripts/fuzz-parser` directory, and replaces them with
`pyproject.toml` and `uv.lock` files. The script is renamed from
`fuzz-parser` to `py-fuzzer` (since it can now also be used to fuzz
red-knot as well as the parser, following
https://github.com/astral-sh/ruff/pull/14566), and moved from the
`scripts/` directory to the `python/` directory, since it's now a
(uv)-pip-installable project in its own right.

I've been resisting this for a while, because conceptually this script
just doesn't feel "complicated" enough to me for it to be a full-blown
package. However, I think it's time to do this. Making it a proper
package has several advantages:
- It means we can run it from the project root using `uv run` without
having to activate a virtual environment and ensure that all required
dependencies are installed into that environment
- Using a `pyproject.toml` file means that we can express that the
project requires Python 3.12+ to run properly; this wasn't possible
before
- I've been running mypy on the project locally when I've been working
on it or reviewing other people's PRs; now I can put the mypy config for
the project in the `pyproject.toml` file

## Test Plan

I manually tested that all the commands detailed in
`python/py-fuzzer/README.md` work for me locally.

---------

Co-authored-by: David Peter <sharkdp@users.noreply.github.com>
2024-11-27 08:09:04 +00:00
Dhruv Manilawala
c84c690f1e Avoid invalid syntax for format-spec with quotes for all Python versions (#14625)
## Summary

fixes: #14608

The logic that was only applied for 3.12+ target version needs to be
applied for other versions as well.

## Test Plan

I've moved the existing test cases for 3.12 only to `f_string.py` so
that it's tested against the default target version.

I think we should probably enabled testing for two target version (pre
3.12 and 3.12) but it won't highlight any issue because the parser
doesn't consider this. Maybe we should enable this once we have target
version specific syntax errors in place
(https://github.com/astral-sh/ruff/issues/6591).
2024-11-27 13:19:33 +05:30
Dhruv Manilawala
0d649f9afd Check that airflow module is seen for AIR001 (#14627) 2024-11-27 07:25:08 +00:00
Lokejoke
82c01aa662 [pylint] Implement len-test (PLC1802) (#14309)
## Summary

This PR implements [`use-implicit-booleaness-not-len` /
`C1802`](https://pylint.pycqa.org/en/latest/user_guide/messages/convention/use-implicit-booleaness-not-len.html)
> For sequences, (strings, lists, tuples), use the fact that empty
sequences are false.

---------

Co-authored-by: xbrtnik1 <524841@mail.muni.cz>
Co-authored-by: xbrtnik1 <xbrtnik1@mail.muni.cz>
2024-11-26 13:30:17 -06:00
Brent Westbrook
9f446faa6c [pyflakes] Avoid false positives in @no_type_check contexts (F821, F722) (#14615) 2024-11-26 19:13:43 +00:00
David Peter
b94d6cf567 [red-knot] Fix panic related to f-strings in annotations (#14613)
## Summary

Fix panics related to expressions without inferred types in invalid
syntax examples like:
```py
x: f"Literal[{1 + 2}]" = 3
```
where the `1 + 2` expression (and its sub-expressions) inside the
annotation did not have an inferred type.

## Test Plan

Added new corpus test.
2024-11-26 16:35:44 +01:00
David Peter
cd0c97211c [red-knot] Update KNOWN_FAILURES (#14612)
## Summary

Remove entry that was prevously fixed in
5a30ec0df6.

## Test Plan

```sh
cargo test -p red_knot_workspace -- --ignored linter_af linter_gz
```
2024-11-26 15:56:42 +01:00
David Peter
0e71c9e3bb [red-knot] Fix unit tests in release mode (#14604)
## Summary

This is about the easiest patch that I can think of. It has a drawback
in that there is no real guarantee this won't happen again. I think this
might be acceptable, given that all of this is a temporary thing.

And we also add a new CI job to prevent regressions like this in the
future.

For the record though, I'm listing alternative approaches I thought of:

- We could get rid of the debug/release distinction and just add `@Todo`
type metadata everywhere. This has possible affects on runtime. The main
reason I didn't follow through with this is that the size of `Type`
increases. We would either have to adapt the `assert_eq_size!` test or
get rid of it. Even if we add messages everywhere and get rid of the
file-and-line-variant in the enum, it's not enough to get back to the
current release-mode size of `Type`.
- We could generally discard `@Todo` meta information when using it in
tests. I think this would be a huge drawback. I like that we can have
the actual messages in the mdtest. And make sure we get the expected
`@Todo` type, not just any `@Todo`. It's also helpful when debugging
tests.

closes #14594

## Test Plan

```rs
cargo nextest run --release
```
2024-11-26 15:40:02 +01:00
Dylan
24c90d6953 [pylint] Do not wrap function calls in parentheses in the fix for unnecessary-dunder-call (PLC2801) (#14601) 2024-11-26 06:47:01 -06:00
Tzu-ping Chung
fbff4dec3a [airflow] Avoid implicit DAG schedule (AIR301) (#14581) 2024-11-26 13:38:18 +01:00
Dhruv Manilawala
f3dac27e9a Fix f-string formatting in assignment statement (#14454)
## Summary

fixes: #13813

This PR fixes a bug in the formatting assignment statement when the
value is an f-string.

This is resolved by using custom best fit layouts if the f-string is (a)
not already a flat f-string (thus, cannot be multiline) and (b) is not a
multiline string (thus, cannot be flattened). So, it is used in cases
like the following:
```py
aaaaaaaaaaaaaaaaaa = f"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
    expression}moreeeeeeeeeeeeeeeee"
```
Which is (a) `FStringLayout::Multiline` and (b) not a multiline.

There are various other examples in the PR diff along with additional
explanation and context as code comments.

## Test Plan

Add multiple test cases for various scenarios.
2024-11-26 15:07:18 +05:30
Simon Brugman
e4cefd9bf9 Extend test cases for flake8-pyi (#14280) 2024-11-26 09:10:38 +01:00
Lokejoke
9e4ee98109 [ruff] Implement invalid-assert-message-literal-argument (RUF040) (#14488)
## Summary

This PR implements new rule discussed
[here](https://github.com/astral-sh/ruff/discussions/14449).
In short, it searches for assert messages which were unintentionally
used as a expression to be matched against.

## Test Plan

`cargo test` and review of `ruff-ecosystem`
2024-11-25 17:41:07 -06:00
Shaygan Hooshyari
557d583e32 Support typing.NoReturn and typing.Never (#14559)
Fix #14558 
## Summary

- Add `typing.NoReturn` and `typing.Never` to known instances and infer
them as `Type::Never`
- Add `is_assignable_to` cases for `Type::Never`

I skipped emitting diagnostic for when a function is annotated as
`NoReturn` but it actually returns.

## Test Plan

Added tests from

https://github.com/python/typing/blob/main/conformance/tests/specialtypes_never.py
except from generics and checking if the return value of the function
and the annotations match.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Carl Meyer <carl@astral.sh>
2024-11-25 21:37:55 +00:00
cake-monotone
f98eebdbab [red-knot] Fix Leaking Narrowing Constraint in ast::ExprIf (#14590)
## Summary

Closes #14588


```py
x: Literal[42, "hello"] = 42 if bool_instance() else "hello"
reveal_type(x)  # revealed: Literal[42] | Literal["hello"]

_ = ... if isinstance(x, str) else ...

# The `isinstance` test incorrectly narrows the type of `x`.
# As a result, `x` is revealed as Literal["hello"], but it should remain Literal[42, "hello"].
reveal_type(x)  # revealed: Literal["hello"]
```

## Test Plan
mdtest included!

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-11-25 10:36:37 -08:00
Simon Brugman
c606bf014e [flake8-pyi] Improve autofix safety for redundant-none-literal (PYI061) (#14583)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-11-25 17:40:57 +00:00
Simon Brugman
e8fce20736 [ruff] Improve autofix safety for never-union (RUF020) (#14589) 2024-11-25 18:35:07 +01:00
Dhruv Manilawala
5a30ec0df6 Avoid inferring invalid expr types for string annotation (#14447)
## Summary

fixes: #14440

## Test Plan

Add a test case with all the invalid expressions in a string annotation
context.
2024-11-25 21:27:03 +05:30
Alex Waygood
fab1b0d546 fuzz-parser: catch exceptions from pysource-minimize (#14586) 2024-11-25 15:14:01 +00:00
Connor Skees
66abef433b red-knot: adapt fuzz-parser to work with red-knot (#14566)
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2024-11-25 13:12:28 +00:00
Harutaka Kawamura
fa22bd604a Fix pytest.mark.parametrize rules to check calls instead of decorators (#14515)
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-11-25 13:55:18 +01:00
Dhruv Manilawala
0c9165fc3a Use Result for failed text document retrieval in LSP requests (#14579)
## Summary

Ref:
https://github.com/astral-sh/ruff-vscode/issues/644#issuecomment-2496588452

## Test Plan

Not sure how to test this as this is mainly to get more context on the
panic that the server is raising.
2024-11-25 15:14:30 +05:30
renovate[bot]
9f6147490b Update NPM Development dependencies (#14577)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 08:54:51 +01:00
renovate[bot]
b7571c3e24 Update Rust crate syn to v2.0.89 (#14573)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 07:46:06 +00:00
renovate[bot]
d178d115f3 Update dependency mdformat to v0.7.19 (#14576)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 08:40:53 +01:00
renovate[bot]
6501782678 Update Rust crate libcst to v1.5.1 (#14570)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 08:39:22 +01:00
renovate[bot]
bca4341dcc Update Rust crate hashbrown to v0.15.2 (#14569)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 08:38:34 +01:00
renovate[bot]
31ede11774 Update Rust crate quick-junit to v0.5.1 (#14572)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 08:38:12 +01:00
renovate[bot]
ba9f881687 Update Rust crate proc-macro2 to v1.0.92 (#14571)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 08:38:00 +01:00
renovate[bot]
4357a0a3c2 Update Rust crate unicode-ident to v1.0.14 (#14574)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 08:36:50 +01:00
renovate[bot]
c18afa93b3 Update Rust crate url to v2.5.4 (#14575)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 08:36:28 +01:00
renovate[bot]
8f04202ee4 Update Rust crate dir-test to 0.4.0 (#14578)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 08:36:06 +01:00
Dhruv Manilawala
efe54081d6 Remove FormatFStringPart (#14448)
## Summary

This is just a small refactor to remove the `FormatFStringPart` as it's
only used in the case when the f-string is not implicitly concatenated
in which case the only part is going to be `FString`. In implicitly
concatenated f-strings, we use `StringLike` instead.
2024-11-25 10:29:22 +05:30
Alex Waygood
ac23c99744 [ruff] Mark fixes for unsorted-dunder-all and unsorted-dunder-slots as unsafe when there are complex comments in the sequence (RUF022, RUF023) (#14560) 2024-11-24 12:49:29 +00:00
InSync
e5c7d87461 Add @astropy/astropy to ecosystem checks (#14565) 2024-11-24 12:47:11 +01:00
Charlie Marsh
de62e39eba Use truthiness check in auto_attribs detection (#14562) 2024-11-23 22:06:10 -05:00
InSync
d285717da8 [ruff] Handle attrs's auto_attribs correctly (RUF009) (#14520)
## Summary

Resolves #14519.

## Test Plan

`cargo nextest run` and `cargo insta test`.
2024-11-23 21:46:38 -05:00
InSync
545e9deba3 [flake8-builtins] Exempt private built-in modules (A005) (#14505)
## Summary

Resolves #12949.

## Test Plan

`cargo nextest run` and `cargo insta test`.
2024-11-23 21:39:04 -05:00
Harutaka Kawamura
e3d792605f [flake8-bugbear] Fix mutable-contextvar-default (B039) to resolve annotated function calls properly (#14532)
## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

Fix #14525

## Test Plan

<!-- How was it tested? -->

New test cases

---------

Signed-off-by: harupy <hkawamura0130@gmail.com>
2024-11-23 21:29:25 -05:00
Harutaka Kawamura
1f303a5eb6 Simplify flake8_pytest_style::rules::fail_call implementation (#14556) 2024-11-23 15:14:28 +01:00
Nikolas Hearp
07d13c6b4a [B028-doc-update] Update documentation for B028 (#14338)
## Summary
Resolves #14289
The documentation for B028 no_explicit_stacklevel is updated to be more
clear.

---------

Co-authored-by: dylwil3 <dylwil3@gmail.com>
2024-11-23 07:45:28 +00:00
Dylan
e1838aac29 Ignore more rules for stub files (#14541)
This PR causes the following rules to ignore stub files, on the grounds
that it is not under the author's control to appease these lints:

- `PLR0904` https://docs.astral.sh/ruff/rules/too-many-public-methods/
- `PLR0913` https://docs.astral.sh/ruff/rules/too-many-arguments/
- `PLR0917`
https://docs.astral.sh/ruff/rules/too-many-positional-arguments/
- `PLW3201` https://docs.astral.sh/ruff/rules/bad-dunder-method-name/
- `SLOT` https://docs.astral.sh/ruff/rules/#flake8-slots-slot
- `FBT` https://docs.astral.sh/ruff/rules/#flake8-boolean-trap-fbt
(except for FBT003 since that involves a function call.)

Progress towards #14535
2024-11-23 07:41:10 +00:00
Carl Meyer
4ba847f250 [red-knot] remove wrong typevar attribute implementations (#14540) 2024-11-22 13:17:16 -08:00
renovate[bot]
13e9fc9362 Update dependency smol-toml to v1.3.1 (#14542)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-22 21:16:05 +00:00
Dylan
3fda2d17c7 [ruff] Auto-add r prefix when string has no backslashes for unraw-re-pattern (RUF039) (#14536)
This PR adds a sometimes-available, safe autofix for [unraw-re-pattern
(RUF039)](https://docs.astral.sh/ruff/rules/unraw-re-pattern/#unraw-re-pattern-ruf039),
which prepends an `r` prefix. It is used only when the string in
question has no backslahses (and also does not have a `u` prefix, since
that causes a syntax error.)

Closes #14527

Notes: 
- Test fixture unchanged, but snapshot changed to include fix messages.
- This fix is automatically only available in preview since the rule
itself is in preview
2024-11-22 15:09:53 -06:00
Harutaka Kawamura
931fa06d85 Extend invalid-envvar-default (PLW1508) to detect os.environ.get (#14512) 2024-11-22 19:13:58 +00:00
Micha Reiser
e53ac7985d Enable logging for directory-renamed test (#14533) 2024-11-22 16:41:46 +00:00
David Salvisberg
e25e7044ba [flake8-type-checking] Adds implementation for TC006 (#14511)
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-11-22 15:22:59 +01:00
Micha Reiser
b80de52592 Consider quotes inside format-specs when choosing the quotes for an f-string (#14493) 2024-11-22 12:43:53 +00:00
Alex Waygood
2917534279 Fix broken link to PYI063 (#14526) 2024-11-22 12:27:52 +00:00
David Peter
f6b2cd5588 [red-knot] Semantic index: handle invalid breaks (#14522)
## Summary

This fix addresses panics related to invalid syntax like the following
where a `break` statement is used in a nested definition inside a
loop:

```py
while True:

    def b():
        x: int

        break
```

closes #14342

## Test Plan

* New corpus regression tests.
* New unit test to make sure we handle nested while loops correctly.
This test is passing on `main`, but can easily fail if the
`is_inside_loop` state isn't properly saved/restored.
2024-11-22 13:13:55 +01:00
Micha Reiser
302fe76c2b Fix unnecessary space around power op in overlong f-string expressions (#14489) 2024-11-22 13:01:22 +01:00
1139 changed files with 22192 additions and 6210 deletions

5
.github/CODEOWNERS vendored
View File

@@ -13,9 +13,10 @@
# flake8-pyi
/crates/ruff_linter/src/rules/flake8_pyi/ @AlexWaygood
# Script for fuzzing the parser
/scripts/fuzz-parser/ @AlexWaygood
# Script for fuzzing the parser/red-knot etc.
/python/py-fuzzer/ @AlexWaygood
# red-knot
/crates/red_knot* @carljm @MichaReiser @AlexWaygood @sharkdp
/crates/ruff_db/ @carljm @MichaReiser @AlexWaygood @sharkdp
/scripts/knot_benchmark/ @carljm @MichaReiser @AlexWaygood @sharkdp

View File

@@ -49,7 +49,7 @@ jobs:
- crates/ruff_text_size/**
- crates/ruff_python_ast/**
- crates/ruff_python_parser/**
- scripts/fuzz-parser/**
- python/py-fuzzer/**
- .github/workflows/ci.yaml
linter:
@@ -82,6 +82,7 @@ jobs:
code:
- "**/*"
- "!**/*.md"
- "crates/red_knot_python_semantic/resources/mdtest/**/*.md"
- "!docs/**"
- "!assets/**"
@@ -157,6 +158,33 @@ jobs:
name: ruff
path: target/debug/ruff
cargo-test-linux-release:
name: "cargo test (linux, release)"
runs-on: depot-ubuntu-22.04-16
needs: determine_changes
if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }}
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: "Install Rust toolchain"
run: rustup show
- name: "Install mold"
uses: rui314/setup-mold@v1
- name: "Install cargo nextest"
uses: taiki-e/install-action@v2
with:
tool: cargo-nextest
- name: "Install cargo insta"
uses: taiki-e/install-action@v2
with:
tool: cargo-insta
- uses: Swatinem/rust-cache@v2
- name: "Run tests"
shell: bash
env:
NEXTEST_PROFILE: "ci"
run: cargo insta test --release --all-features --unreferenced reject --test-runner nextest
cargo-test-windows:
name: "cargo test (windows)"
runs-on: windows-latest-xlarge
@@ -212,7 +240,6 @@ jobs:
cargo-build-release:
name: "cargo build (release)"
runs-on: macos-latest
needs: determine_changes
if: ${{ github.ref == 'refs/heads/main' }}
timeout-minutes: 20
steps:
@@ -291,13 +318,7 @@ jobs:
FORCE_COLOR: 1
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Install Python requirements
run: uv pip install -r scripts/fuzz-parser/requirements.txt --system
- uses: astral-sh/setup-uv@v4
- uses: actions/download-artifact@v4
name: Download Ruff binary to test
id: download-cached-binary
@@ -309,7 +330,15 @@ jobs:
# Make executable, since artifact download doesn't preserve this
chmod +x ${{ steps.download-cached-binary.outputs.download-path }}/ruff
python scripts/fuzz-parser/fuzz.py 0-500 --test-executable ${{ steps.download-cached-binary.outputs.download-path }}/ruff
(
uvx \
--python=${{ env.PYTHON_VERSION }} \
--from=./python/py-fuzzer \
fuzz \
--test-executable=${{ steps.download-cached-binary.outputs.download-path }}/ruff \
--bin=ruff \
0-500
)
scripts:
name: "test scripts"
@@ -354,7 +383,7 @@ jobs:
name: ruff
path: target/debug
- uses: dawidd6/action-download-artifact@v6
- uses: dawidd6/action-download-artifact@v7
name: Download baseline Ruff binary
with:
name: ruff
@@ -530,7 +559,7 @@ jobs:
- name: "Install Rust toolchain"
run: rustup show
- name: Install uv
uses: astral-sh/setup-uv@v3
uses: astral-sh/setup-uv@v4
- uses: Swatinem/rust-cache@v2
- name: "Install Insiders dependencies"
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}

View File

@@ -32,13 +32,7 @@ jobs:
if: ${{ github.repository == 'astral-sh/ruff' || github.event_name != 'schedule' }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Install Python requirements
run: uv pip install -r scripts/fuzz-parser/requirements.txt --system
- uses: astral-sh/setup-uv@v4
- name: "Install Rust toolchain"
run: rustup show
- name: "Install mold"
@@ -49,7 +43,16 @@ jobs:
# but this is outweighed by the fact that a release build takes *much* longer to compile in CI
run: cargo build --locked
- name: Fuzz
run: python scripts/fuzz-parser/fuzz.py $(shuf -i 0-9999999999999999999 -n 1000) --test-executable target/debug/ruff
run: |
(
uvx \
--python=3.12 \
--from=./python/py-fuzzer \
fuzz \
--test-executable=target/debug/ruff \
--bin=ruff \
$(shuf -i 0-9999999999999999999 -n 1000)
)
create-issue-on-failure:
name: Create an issue if the daily fuzz surfaced any bugs

View File

@@ -17,7 +17,7 @@ jobs:
comment:
runs-on: ubuntu-latest
steps:
- uses: dawidd6/action-download-artifact@v6
- uses: dawidd6/action-download-artifact@v7
name: Download pull request number
with:
name: pr-number
@@ -33,7 +33,7 @@ jobs:
echo "pr-number=$(<pr-number)" >> $GITHUB_OUTPUT
fi
- uses: dawidd6/action-download-artifact@v6
- uses: dawidd6/action-download-artifact@v7
name: "Download ecosystem results"
id: download-ecosystem-result
if: steps.pr-number.outputs.pr-number

View File

@@ -47,7 +47,7 @@ jobs:
working-directory: playground
- name: "Deploy to Cloudflare Pages"
if: ${{ env.CF_API_TOKEN_EXISTS == 'true' }}
uses: cloudflare/wrangler-action@v3.12.1
uses: cloudflare/wrangler-action@v3.13.0
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CF_ACCOUNT_ID }}

View File

@@ -22,7 +22,7 @@ jobs:
id-token: write
steps:
- name: "Install uv"
uses: astral-sh/setup-uv@v3
uses: astral-sh/setup-uv@v4
- uses: actions/download-artifact@v4
with:
pattern: wheels-*

View File

@@ -22,7 +22,7 @@ repos:
- id: validate-pyproject
- repo: https://github.com/executablebooks/mdformat
rev: 0.7.18
rev: 0.7.19
hooks:
- id: mdformat
additional_dependencies:
@@ -36,7 +36,7 @@ repos:
)$
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.42.0
rev: v0.43.0
hooks:
- id: markdownlint-fix
exclude: |
@@ -59,7 +59,7 @@ repos:
- black==24.10.0
- repo: https://github.com/crate-ci/typos
rev: v1.27.3
rev: v1.28.1
hooks:
- id: typos
@@ -73,7 +73,7 @@ repos:
pass_filenames: false # This makes it a lot faster
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.4
rev: v0.8.1
hooks:
- id: ruff-format
- id: ruff
@@ -83,7 +83,7 @@ repos:
# Prettier
- repo: https://github.com/rbubley/mirrors-prettier
rev: v3.3.3
rev: v3.4.1
hooks:
- id: prettier
types: [yaml]

View File

@@ -192,7 +192,7 @@ flag or `unsafe-fixes` configuration option can be used to enable unsafe fixes.
See the [docs](https://docs.astral.sh/ruff/configuration/#fix-safety) for details.
### Remove formatter-conflicting rules from the default rule set ([#7900](https://github.com/astral-sh/ruff/pull/7900))
### Remove formatter-conflicting rules from the default rule set ([#7900](https://github.com/astral-sh/ruff/pull/7900))
Previously, Ruff enabled all implemented rules in Pycodestyle (`E`) by default. Ruff now only includes the
Pycodestyle prefixes `E4`, `E7`, and `E9` to exclude rules that conflict with automatic formatters. Consequently,

View File

@@ -1,5 +1,46 @@
# Changelog
## 0.8.1
### Preview features
- Formatter: Avoid invalid syntax for format-spec with quotes for all Python versions ([#14625](https://github.com/astral-sh/ruff/pull/14625))
- Formatter: Consider quotes inside format-specs when choosing the quotes for an f-string ([#14493](https://github.com/astral-sh/ruff/pull/14493))
- Formatter: Do not consider f-strings with escaped newlines as multiline ([#14624](https://github.com/astral-sh/ruff/pull/14624))
- Formatter: Fix f-string formatting in assignment statement ([#14454](https://github.com/astral-sh/ruff/pull/14454))
- Formatter: Fix unnecessary space around power operator (`**`) in overlong f-string expressions ([#14489](https://github.com/astral-sh/ruff/pull/14489))
- \[`airflow`\] Avoid implicit `schedule` argument to `DAG` and `@dag` (`AIR301`) ([#14581](https://github.com/astral-sh/ruff/pull/14581))
- \[`flake8-builtins`\] Exempt private built-in modules (`A005`) ([#14505](https://github.com/astral-sh/ruff/pull/14505))
- \[`flake8-pytest-style`\] Fix `pytest.mark.parametrize` rules to check calls instead of decorators ([#14515](https://github.com/astral-sh/ruff/pull/14515))
- \[`flake8-type-checking`\] Implement `runtime-cast-value` (`TC006`) ([#14511](https://github.com/astral-sh/ruff/pull/14511))
- \[`flake8-type-checking`\] Implement `unquoted-type-alias` (`TC007`) and `quoted-type-alias` (`TC008`) ([#12927](https://github.com/astral-sh/ruff/pull/12927))
- \[`flake8-use-pathlib`\] Recommend `Path.iterdir()` over `os.listdir()` (`PTH208`) ([#14509](https://github.com/astral-sh/ruff/pull/14509))
- \[`pylint`\] Extend `invalid-envvar-default` to detect `os.environ.get` (`PLW1508`) ([#14512](https://github.com/astral-sh/ruff/pull/14512))
- \[`pylint`\] Implement `len-test` (`PLC1802`) ([#14309](https://github.com/astral-sh/ruff/pull/14309))
- \[`refurb`\] Fix bug where methods defined using lambdas were flagged by `FURB118` ([#14639](https://github.com/astral-sh/ruff/pull/14639))
- \[`ruff`\] Auto-add `r` prefix when string has no backslashes for `unraw-re-pattern` (`RUF039`) ([#14536](https://github.com/astral-sh/ruff/pull/14536))
- \[`ruff`\] Implement `invalid-assert-message-literal-argument` (`RUF040`) ([#14488](https://github.com/astral-sh/ruff/pull/14488))
- \[`ruff`\] Implement `unnecessary-nested-literal` (`RUF041`) ([#14323](https://github.com/astral-sh/ruff/pull/14323))
- \[`ruff`\] Implement `unnecessary-regular-expression` (`RUF055`) ([#14659](https://github.com/astral-sh/ruff/pull/14659))
### Rule changes
- Ignore more rules for stub files ([#14541](https://github.com/astral-sh/ruff/pull/14541))
- \[`pep8-naming`\] Eliminate false positives for single-letter names (`N811`, `N814`) ([#14584](https://github.com/astral-sh/ruff/pull/14584))
- \[`pyflakes`\] Avoid false positives in `@no_type_check` contexts (`F821`, `F722`) ([#14615](https://github.com/astral-sh/ruff/pull/14615))
- \[`ruff`\] Detect redirected-noqa in file-level comments (`RUF101`) ([#14635](https://github.com/astral-sh/ruff/pull/14635))
- \[`ruff`\] Mark fixes for `unsorted-dunder-all` and `unsorted-dunder-slots` as unsafe when there are complex comments in the sequence (`RUF022`, `RUF023`) ([#14560](https://github.com/astral-sh/ruff/pull/14560))
### Bug fixes
- Avoid fixing code to `None | None` for `redundant-none-literal` (`PYI061`) and `never-union` (`RUF020`) ([#14583](https://github.com/astral-sh/ruff/pull/14583), [#14589](https://github.com/astral-sh/ruff/pull/14589))
- \[`flake8-bugbear`\] Fix `mutable-contextvar-default` to resolve annotated function calls properly (`B039`) ([#14532](https://github.com/astral-sh/ruff/pull/14532))
- \[`flake8-pyi`, `ruff`\] Fix traversal of nested literals and unions (`PYI016`, `PYI051`, `PYI055`, `PYI062`, `RUF041`) ([#14641](https://github.com/astral-sh/ruff/pull/14641))
- \[`flake8-pyi`\] Avoid rewriting invalid type expressions in `unnecessary-type-union` (`PYI055`) ([#14660](https://github.com/astral-sh/ruff/pull/14660))
- \[`flake8-type-checking`\] Avoid syntax errors and type checking problem for quoted annotations autofix (`TC003`, `TC006`) ([#14634](https://github.com/astral-sh/ruff/pull/14634))
- \[`pylint`\] Do not wrap function calls in parentheses in the fix for unnecessary-dunder-call (`PLC2801`) ([#14601](https://github.com/astral-sh/ruff/pull/14601))
- \[`ruff`\] Handle `attrs`'s `auto_attribs` correctly (`RUF009`) ([#14520](https://github.com/astral-sh/ruff/pull/14520))
## 0.8.0
Check out the [blog post](https://astral.sh/blog/ruff-v0.8.0) for a migration guide and overview of the changes!
@@ -57,7 +98,7 @@ The following rules have been stabilized and are no longer in preview:
- [`fast-api-redundant-response-model`](https://docs.astral.sh/ruff/rules/fast-api-redundant-response-model/) (`FAST001`)
- [`fast-api-non-annotated-dependency`](https://docs.astral.sh/ruff/rules/fast-api-non-annotated-dependency/) (`FAST002`)
- [`dict-index-missing-items`](https://docs.astral.sh/ruff/rules/dict-index-missing-items/) (`PLC0206`)
- [`pep484-style-positional-only-argument`](https://docs.astral.sh/ruff/rules/pep484-style-positional-only-argument/) (`PYI063`)
- [`pep484-style-positional-only-parameter`](https://docs.astral.sh/ruff/rules/pep484-style-positional-only-parameter/) (`PYI063`)
- [`redundant-final-literal`](https://docs.astral.sh/ruff/rules/redundant-final-literal/) (`PYI064`)
- [`bad-version-info-order`](https://docs.astral.sh/ruff/rules/bad-version-info-order/) (`PYI066`)
- [`parenthesize-chained-operators`](https://docs.astral.sh/ruff/rules/parenthesize-chained-operators/) (`RUF021`)
@@ -216,7 +257,7 @@ The following fixes have been stabilized:
### Preview features
- Fix `E221` and `E222` to flag missing or extra whitespace around `==` operator ([#13890](https://github.com/astral-sh/ruff/pull/13890))
- Formatter: Alternate quotes for strings inside f-strings in preview ([#13860](https://github.com/astral-sh/ruff/pull/13860))
- Formatter: Alternate quotes for strings inside f-strings in preview ([#13860](https://github.com/astral-sh/ruff/pull/13860))
- Formatter: Join implicit concatenated strings when they fit on a line ([#13663](https://github.com/astral-sh/ruff/pull/13663))
- \[`pylint`\] Restrict `iteration-over-set` to only work on sets of literals (`PLC0208`) ([#13731](https://github.com/astral-sh/ruff/pull/13731))
@@ -1077,7 +1118,7 @@ The following deprecated CLI commands have been removed:
### Preview features
- \[`flake8-bugbear`\] Implement `return-in-generator` (`B901`) ([#11644](https://github.com/astral-sh/ruff/pull/11644))
- \[`flake8-pyi`\] Implement `PYI063` ([#11699](https://github.com/astral-sh/ruff/pull/11699))
- \[`flake8-pyi`\] Implement `pep484-style-positional-only-parameter` (`PYI063`) ([#11699](https://github.com/astral-sh/ruff/pull/11699))
- \[`pygrep_hooks`\] Check blanket ignores via file-level pragmas (`PGH004`) ([#11540](https://github.com/astral-sh/ruff/pull/11540))
### Rule changes
@@ -1231,7 +1272,7 @@ To read more about this exciting milestone, check out our [blog post](https://as
### Preview features
- \[`pycodestyle`\] Ignore end-of-line comments when determining blank line rules ([#11342](https://github.com/astral-sh/ruff/pull/11342))
- \[`pylint`\] Detect `pathlib.Path.open` calls in `unspecified-encoding` (`PLW1514`) ([#11288](https://github.com/astral-sh/ruff/pull/11288))
- \[`pylint`\] Detect `pathlib.Path.open` calls in `unspecified-encoding` (`PLW1514`) ([#11288](https://github.com/astral-sh/ruff/pull/11288))
- \[`flake8-pyi`\] Implement `PYI059` (`generic-not-last-base-class`) ([#11233](https://github.com/astral-sh/ruff/pull/11233))
- \[`flake8-pyi`\] Implement `PYI062` (`duplicate-literal-member`) ([#11269](https://github.com/astral-sh/ruff/pull/11269))
@@ -1606,7 +1647,7 @@ To setup `ruff server` with your editor, refer to the [README.md](https://github
- \[`pycodestyle`\] Do not ignore lines before the first logical line in blank lines rules. ([#10382](https://github.com/astral-sh/ruff/pull/10382))
- \[`pycodestyle`\] Do not trigger `E225` and `E275` when the next token is a ')' ([#10315](https://github.com/astral-sh/ruff/pull/10315))
- \[`pylint`\] Avoid false-positive slot non-assignment for `__dict__` (`PLE0237`) ([#10348](https://github.com/astral-sh/ruff/pull/10348))
- Gate f-string struct size test for Rustc \< 1.76 ([#10371](https://github.com/astral-sh/ruff/pull/10371))
- Gate f-string struct size test for Rustc < 1.76 ([#10371](https://github.com/astral-sh/ruff/pull/10371))
### Documentation

View File

@@ -139,7 +139,7 @@ At a high level, the steps involved in adding a new lint rule are as follows:
1. Create a file for your rule (e.g., `crates/ruff_linter/src/rules/flake8_bugbear/rules/assert_false.rs`).
1. In that file, define a violation struct (e.g., `pub struct AssertFalse`). You can grep for
`#[violation]` to see examples.
`#[derive(ViolationMetadata)]` to see examples.
1. In that file, define a function that adds the violation to the diagnostic list as appropriate
(e.g., `pub(crate) fn assert_false`) based on whatever inputs are required for the rule (e.g.,
@@ -863,7 +863,7 @@ each configuration file.
The package root is used to determine a file's "module path". Consider, again, `baz.py`. In that
case, `./my_project/src/foo` was identified as the package root, so the module path for `baz.py`
would resolve to `foo.bar.baz` — as computed by taking the relative path from the package root
would resolve to `foo.bar.baz` — as computed by taking the relative path from the package root
(inclusive of the root itself). The module path can be thought of as "the path you would use to
import the module" (e.g., `import foo.bar.baz`).

267
Cargo.lock generated
View File

@@ -413,7 +413,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -693,7 +693,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim 0.10.0",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -704,7 +704,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
dependencies = [
"darling_core",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -758,23 +758,23 @@ dependencies = [
[[package]]
name = "dir-test"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c44bdf9319ad5223afb7eb15a7110452b0adf0373ea6756561b2c708eef0dd1"
checksum = "b12781621d53fd9087021f5a338df5c57c04f84a6231c1f4726f45e2e333470b"
dependencies = [
"dir-test-macros",
]
[[package]]
name = "dir-test-macros"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "644f96047137dfaa7a09e34d4623f9e52a1926ecc25ba32ad2ba3fc422536b25"
checksum = "1340852f50b2285d01a7f598cc5d08b572669c3e09e614925175cc3c26787b91"
dependencies = [
"glob",
"proc-macro2",
"quote",
"syn 1.0.109",
"syn",
]
[[package]]
@@ -826,7 +826,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -1068,9 +1068,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.1"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "hashlink"
@@ -1246,7 +1246,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -1314,12 +1314,12 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.6.0"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [
"equivalent",
"hashbrown 0.15.1",
"hashbrown 0.15.2",
"serde",
]
@@ -1420,7 +1420,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -1485,10 +1485,11 @@ checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae"
[[package]]
name = "js-sys"
version = "0.3.72"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705"
dependencies = [
"once_cell",
"wasm-bindgen",
]
@@ -1520,15 +1521,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.164"
version = "0.2.167"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
[[package]]
name = "libcst"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1586dd7a857d8a61a577afde1a24cc9573ff549eff092d5ce968b1ec93cc61b6"
checksum = "fa3e60579a8cba3d86aa4a5f7fc98973cc0fd2ac270bf02f85a9bef09700b075"
dependencies = [
"chic",
"libcst_derive",
@@ -1546,7 +1547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2ae40017ac09cd2c6a53504cb3c871c7f2b41466eac5bc66ba63f39073b467b"
dependencies = [
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -1710,9 +1711,9 @@ checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c"
[[package]]
name = "newtype-uuid"
version = "1.1.0"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3526cb7c660872e401beaf3297f95f548ce3b4b4bdd8121b7c0713771d7c4a6e"
checksum = "4c8781e2ef64806278a55ad223f0bc875772fd40e1fe6e73e8adbf027817229d"
dependencies = [
"uuid",
]
@@ -1833,9 +1834,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "ordermap"
version = "0.5.3"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31f2bd7b03bf2c767e1bb7b91505dbe022833776e60480275e6f2fb0db0c7503"
checksum = "f80a48eb68b6a7da9829b8b0429011708f775af80676a91063d023a66a656106"
dependencies = [
"indexmap",
]
@@ -1910,9 +1911,9 @@ checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42"
[[package]]
name = "pathdiff"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361"
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
[[package]]
name = "peg"
@@ -1965,7 +1966,7 @@ dependencies = [
"once_cell",
"pep440_rs",
"regex",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"serde",
"smallvec",
"thiserror 1.0.67",
@@ -2012,7 +2013,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -2127,9 +2128,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.89"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
@@ -2150,24 +2151,24 @@ dependencies = [
[[package]]
name = "quick-junit"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62ffd2f9a162cfae131bed6d9d1ed60adced33be340a94f96952897d7cb0c240"
checksum = "3ed1a693391a16317257103ad06a88c6529ac640846021da7c435a06fffdacd7"
dependencies = [
"chrono",
"indexmap",
"newtype-uuid",
"quick-xml",
"strip-ansi-escapes",
"thiserror 1.0.67",
"thiserror 2.0.3",
"uuid",
]
[[package]]
name = "quick-xml"
version = "0.36.1"
version = "0.37.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96a05e2e8efddfa51a84ca47cec303fac86c8541b686d37cac5efc0e094417bc"
checksum = "f22f29bdff3987b4d8632ef95fd6424ec7e4e0a57e2f4fc63e489e75357f6a03"
dependencies = [
"memchr",
]
@@ -2266,7 +2267,7 @@ dependencies = [
"compact_str",
"countme",
"dir-test",
"hashbrown 0.15.1",
"hashbrown 0.15.2",
"indexmap",
"insta",
"itertools 0.13.0",
@@ -2282,7 +2283,7 @@ dependencies = [
"ruff_python_stdlib",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"salsa",
"serde",
"smallvec",
@@ -2309,7 +2310,7 @@ dependencies = [
"ruff_python_ast",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"serde",
"serde_json",
"shellexpand",
@@ -2322,6 +2323,7 @@ name = "red_knot_test"
version = "0.0.0"
dependencies = [
"anyhow",
"camino",
"colored",
"memchr",
"red_knot_python_semantic",
@@ -2332,7 +2334,7 @@ dependencies = [
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"salsa",
"smallvec",
]
@@ -2380,7 +2382,7 @@ dependencies = [
"ruff_db",
"ruff_python_ast",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"salsa",
"serde",
"thiserror 2.0.3",
@@ -2489,7 +2491,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.8.0"
version = "0.8.1"
dependencies = [
"anyhow",
"argfile",
@@ -2529,7 +2531,7 @@ dependencies = [
"ruff_source_file",
"ruff_text_size",
"ruff_workspace",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"serde",
"serde_json",
"shellexpand",
@@ -2560,7 +2562,7 @@ dependencies = [
"ruff_python_formatter",
"ruff_python_parser",
"ruff_python_trivia",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"serde",
"serde_json",
"tikv-jemallocator",
@@ -2602,7 +2604,7 @@ dependencies = [
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"salsa",
"serde",
"tempfile",
@@ -2671,7 +2673,7 @@ dependencies = [
"ruff_cache",
"ruff_macros",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"schemars",
"serde",
"static_assertions",
@@ -2708,7 +2710,7 @@ dependencies = [
[[package]]
name = "ruff_linter"
version = "0.8.0"
version = "0.8.1"
dependencies = [
"aho-corasick",
"annotate-snippets 0.9.2",
@@ -2749,7 +2751,7 @@ dependencies = [
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"schemars",
"serde",
"serde_json",
@@ -2775,7 +2777,7 @@ dependencies = [
"proc-macro2",
"quote",
"ruff_python_trivia",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -2811,7 +2813,7 @@ dependencies = [
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"schemars",
"serde",
]
@@ -2857,7 +2859,7 @@ dependencies = [
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"schemars",
"serde",
"serde_json",
@@ -2904,7 +2906,7 @@ dependencies = [
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"static_assertions",
"unicode-ident",
"unicode-normalization",
@@ -2935,7 +2937,7 @@ dependencies = [
"ruff_python_parser",
"ruff_python_stdlib",
"ruff_text_size",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"schemars",
"serde",
]
@@ -2993,7 +2995,7 @@ dependencies = [
"ruff_source_file",
"ruff_text_size",
"ruff_workspace",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"serde",
"serde_json",
"shellexpand",
@@ -3023,7 +3025,7 @@ dependencies = [
[[package]]
name = "ruff_wasm"
version = "0.8.0"
version = "0.8.1"
dependencies = [
"console_error_panic_hook",
"console_log",
@@ -3074,7 +3076,7 @@ dependencies = [
"ruff_python_semantic",
"ruff_python_stdlib",
"ruff_source_file",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"schemars",
"serde",
"shellexpand",
@@ -3101,9 +3103,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-hash"
version = "2.0.0"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]]
name = "rustix"
@@ -3120,9 +3122,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.23.10"
version = "0.23.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402"
checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
dependencies = [
"log",
"once_cell",
@@ -3135,15 +3137,15 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
version = "1.7.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
[[package]]
name = "rustls-webpki"
version = "0.102.5"
version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78"
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [
"ring",
"rustls-pki-types",
@@ -3175,7 +3177,7 @@ dependencies = [
"indexmap",
"lazy_static",
"parking_lot",
"rustc-hash 2.0.0",
"rustc-hash 2.1.0",
"salsa-macro-rules",
"salsa-macros",
"smallvec",
@@ -3195,7 +3197,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
"synstructure",
]
@@ -3229,7 +3231,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -3278,7 +3280,7 @@ checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -3289,7 +3291,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -3312,7 +3314,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -3353,7 +3355,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -3387,9 +3389,9 @@ dependencies = [
[[package]]
name = "similar"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
[[package]]
name = "siphasher"
@@ -3461,7 +3463,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -3472,20 +3474,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "1.0.109"
version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
@@ -3500,7 +3491,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -3563,7 +3554,7 @@ dependencies = [
"cfg-if",
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -3574,7 +3565,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
"test-case-core",
]
@@ -3604,7 +3595,7 @@ checksum = "b607164372e89797d78b8e23a6d67d5d1038c1c65efd52e1389ef8b77caba2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -3615,7 +3606,7 @@ checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -3719,9 +3710,9 @@ dependencies = [
[[package]]
name = "tracing"
version = "0.1.40"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"log",
"pin-project-lite",
@@ -3731,20 +3722,20 @@ dependencies = [
[[package]]
name = "tracing-attributes"
version = "0.1.27"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.32"
version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
dependencies = [
"once_cell",
"valuable",
@@ -3786,9 +3777,9 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
dependencies = [
"matchers",
"nu-ansi-term 0.46.0",
@@ -3876,9 +3867,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.13"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "unicode-normalization"
@@ -3937,25 +3928,28 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "ureq"
version = "2.10.1"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a"
checksum = "b30e6f97efe1fa43535ee241ee76967d3ff6ff3953ebb430d8d55c5393029e7b"
dependencies = [
"base64 0.22.0",
"flate2",
"litemap",
"log",
"once_cell",
"rustls",
"rustls-pki-types",
"url",
"webpki-roots",
"yoke",
"zerofrom",
]
[[package]]
name = "url"
version = "2.5.3"
version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada"
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
dependencies = [
"form_urlencoded",
"idna",
@@ -4007,7 +4001,7 @@ checksum = "6b91f57fe13a38d0ce9e28a03463d8d3c2468ed03d75375110ec71d93b449a08"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -4082,9 +4076,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.95"
version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c"
dependencies = [
"cfg-if",
"once_cell",
@@ -4093,36 +4087,37 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.95"
version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.45"
version = "0.4.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d"
dependencies = [
"cfg-if",
"js-sys",
"once_cell",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.95"
version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -4130,32 +4125,32 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.95"
version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.95"
version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49"
[[package]]
name = "wasm-bindgen-test"
version = "0.3.45"
version = "0.3.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d381749acb0943d357dcbd8f0b100640679883fcdeeef04def49daf8d33a5426"
checksum = "3d919bb60ebcecb9160afee6c71b43a58a4f0517a2de0054cd050d02cec08201"
dependencies = [
"console_error_panic_hook",
"js-sys",
"minicov",
"once_cell",
"scoped-tls",
"wasm-bindgen",
"wasm-bindgen-futures",
@@ -4164,20 +4159,20 @@ dependencies = [
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.45"
version = "0.3.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0"
checksum = "222ebde6ea87fbfa6bdd2e9f1fd8a91d60aee5db68792632176c4e16a74fc7d8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
name = "web-sys"
version = "0.3.69"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -4473,7 +4468,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
"synstructure",
]
@@ -4494,7 +4489,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]
@@ -4514,7 +4509,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
"synstructure",
]
@@ -4543,7 +4538,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
"syn",
]
[[package]]

View File

@@ -65,7 +65,7 @@ compact_str = "0.8.0"
criterion = { version = "0.5.1", default-features = false }
crossbeam = { version = "0.8.4" }
dashmap = { version = "6.0.1" }
dir-test = { version = "0.3.0" }
dir-test = { version = "0.4.0" }
dunce = { version = "1.0.5" }
drop_bomb = { version = "0.1.5" }
env_logger = { version = "0.11.0" }

View File

@@ -136,8 +136,8 @@ curl -LsSf https://astral.sh/ruff/install.sh | sh
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
# For a specific version.
curl -LsSf https://astral.sh/ruff/0.8.0/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.8.0/install.ps1 | iex"
curl -LsSf https://astral.sh/ruff/0.8.1/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.8.1/install.ps1 | iex"
```
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
@@ -170,7 +170,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.8.0
rev: v0.8.1
hooks:
# Run the linter.
- id: ruff

View File

@@ -1,21 +1,25 @@
doc-valid-idents = [
"..",
"CodeQL",
"FastAPI",
"IPython",
"LangChain",
"LibCST",
"McCabe",
"NumPy",
"SCREAMING_SNAKE_CASE",
"SQLAlchemy",
"StackOverflow",
"PyCharm",
"..",
"CodeQL",
"FastAPI",
"IPython",
"LangChain",
"LibCST",
"McCabe",
"NumPy",
"SCREAMING_SNAKE_CASE",
"SQLAlchemy",
"StackOverflow",
"PyCharm",
"SNMPv1",
"SNMPv2",
"SNMPv3",
"PyFlakes"
]
ignore-interior-mutability = [
# Interned is read-only. The wrapped `Rc` never gets updated.
"ruff_formatter::format_element::Interned",
# The expression is read-only.
"ruff_python_ast::hashable::HashableExpr",
# Interned is read-only. The wrapped `Rc` never gets updated.
"ruff_formatter::format_element::Interned",
# The expression is read-only.
"ruff_python_ast::hashable::HashableExpr",
]

View File

@@ -103,7 +103,7 @@ called **once**.
## Profiling
Red Knot generates a folded stack trace to the current directory named `tracing.folded` when setting the environment variable `RED_KNOT_LOG_PROFILE` to `1` or `true`.
Red Knot generates a folded stack trace to the current directory named `tracing.folded` when setting the environment variable `RED_KNOT_LOG_PROFILE` to `1` or `true`.
```bash
RED_KNOT_LOG_PROFILE=1 red_knot -- --current-directory=../test -vvv

View File

@@ -4,7 +4,6 @@ use std::io::Write;
use std::time::Duration;
use anyhow::{anyhow, Context};
use red_knot_python_semantic::{resolve_module, ModuleName, Program, PythonVersion, SitePackages};
use red_knot_workspace::db::{Db, RootDatabase};
use red_knot_workspace::watch;
@@ -14,7 +13,7 @@ use red_knot_workspace::workspace::WorkspaceMetadata;
use ruff_db::files::{system_path_to_file, File, FileError};
use ruff_db::source::source_text;
use ruff_db::system::{OsSystem, SystemPath, SystemPathBuf};
use ruff_db::testing::setup_logging;
use ruff_db::testing::{setup_logging, setup_logging_with_filter};
use ruff_db::Upcast;
struct TestCase {
@@ -47,6 +46,8 @@ impl TestCase {
}
fn try_stop_watch(&mut self, timeout: Duration) -> Option<Vec<watch::ChangeEvent>> {
tracing::debug!("Try stopping watch with timeout {:?}", timeout);
let watcher = self
.watcher
.take()
@@ -56,8 +57,11 @@ impl TestCase {
.changes_receiver
.recv_timeout(timeout)
.unwrap_or_default();
watcher.flush();
tracing::debug!("Flushed file watcher");
watcher.stop();
tracing::debug!("Stopping file watcher");
for event in &self.changes_receiver {
all_events.extend(event);
@@ -600,6 +604,8 @@ fn directory_moved_to_trash() -> anyhow::Result<()> {
#[test]
fn directory_renamed() -> anyhow::Result<()> {
let _tracing = setup_logging_with_filter("file_watching=TRACE,red_knot=TRACE");
let mut case = setup([
("bar.py", "import sub.a"),
("sub/__init__.py", ""),
@@ -640,6 +646,10 @@ fn directory_renamed() -> anyhow::Result<()> {
let changes = case.stop_watch();
for event in &changes {
tracing::debug!("Event: {:?}", event);
}
case.apply_changes(changes);
// `import sub.a` should no longer resolve

View File

@@ -0,0 +1,128 @@
# `LiteralString`
`LiteralString` represents a string that is either defined directly within the source code or is
made up of such components.
Parts of the testcases defined here were adapted from [the specification's examples][1].
## Usages
### Valid places
It can be used anywhere a type is accepted:
```py
from typing import LiteralString
x: LiteralString
def f():
reveal_type(x) # revealed: LiteralString
```
### Within `Literal`
`LiteralString` cannot be used within `Literal`:
```py
from typing import Literal, LiteralString
bad_union: Literal["hello", LiteralString] # error: [invalid-literal-parameter]
bad_nesting: Literal[LiteralString] # error: [invalid-literal-parameter]
```
### Parametrized
`LiteralString` cannot be parametrized.
```py
from typing import LiteralString
a: LiteralString[str] # error: [invalid-type-parameter]
b: LiteralString["foo"] # error: [invalid-type-parameter]
```
### As a base class
Subclassing `LiteralString` leads to a runtime error.
```py
from typing import LiteralString
class C(LiteralString): ... # error: [invalid-base]
```
## Inference
### Common operations
```py
foo: LiteralString = "foo"
reveal_type(foo) # revealed: Literal["foo"]
bar: LiteralString = "bar"
reveal_type(foo + bar) # revealed: Literal["foobar"]
baz: LiteralString = "baz"
baz += foo
reveal_type(baz) # revealed: Literal["bazfoo"]
qux = (foo, bar)
reveal_type(qux) # revealed: tuple[Literal["foo"], Literal["bar"]]
# TODO: Infer "LiteralString"
reveal_type(foo.join(qux)) # revealed: @Todo(call todo)
template: LiteralString = "{}, {}"
reveal_type(template) # revealed: Literal["{}, {}"]
# TODO: Infer `LiteralString`
reveal_type(template.format(foo, bar)) # revealed: @Todo(call todo)
```
### Assignability
`Literal[""]` is assignable to `LiteralString`, and `LiteralString` is assignable to `str`, but not
vice versa.
```py
def coinflip() -> bool:
return True
foo_1: Literal["foo"] = "foo"
bar_1: LiteralString = foo_1 # fine
foo_2 = "foo" if coinflip() else "bar"
reveal_type(foo_2) # revealed: Literal["foo", "bar"]
bar_2: LiteralString = foo_2 # fine
foo_3: LiteralString = "foo" * 1_000_000_000
bar_3: str = foo_2 # fine
baz_1: str = str()
qux_1: LiteralString = baz_1 # error: [invalid-assignment]
baz_2: LiteralString = "baz" * 1_000_000_000
qux_2: Literal["qux"] = baz_2 # error: [invalid-assignment]
baz_3 = "foo" if coinflip() else 1
reveal_type(baz_3) # revealed: Literal["foo"] | Literal[1]
qux_3: LiteralString = baz_3 # error: [invalid-assignment]
```
### Narrowing
```py
lorem: LiteralString = "lorem" * 1_000_000_000
reveal_type(lorem) # revealed: LiteralString
if lorem == "ipsum":
reveal_type(lorem) # revealed: Literal["ipsum"]
reveal_type(lorem) # revealed: LiteralString
if "" < lorem == "ipsum":
reveal_type(lorem) # revealed: Literal["ipsum"]
```
[1]: https://typing.readthedocs.io/en/latest/spec/literal.html#literalstring

View File

@@ -0,0 +1,62 @@
# NoReturn & Never
`NoReturn` is used to annotate the return type for functions that never return. `Never` is the
bottom type, representing the empty set of Python objects. These two annotations can be used
interchangeably.
## Function Return Type Annotation
```py
from typing import NoReturn
def stop() -> NoReturn:
raise RuntimeError("no way")
# revealed: Never
reveal_type(stop())
```
## Assignment
```py
from typing import NoReturn, Never, Any
# error: [invalid-type-parameter] "Type `typing.Never` expected no type parameter"
x: Never[int]
a1: NoReturn
# TODO: Test `Never` is only available in python >= 3.11
a2: Never
b1: Any
b2: int
def f():
# revealed: Never
reveal_type(a1)
# revealed: Never
reveal_type(a2)
# Never is assignable to all types.
v1: int = a1
v2: str = a1
# Other types are not assignable to Never except for Never (and Any).
v3: Never = b1
v4: Never = a2
v5: Any = b2
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to `Never`"
v6: Never = 1
```
## Typing Extensions
```py
from typing_extensions import NoReturn, Never
x: NoReturn
y: Never
def f():
# revealed: Never
reveal_type(x)
# revealed: Never
reveal_type(y)
```

View File

@@ -189,3 +189,31 @@ reveal_type(d) # revealed: Foo
## Parameter
TODO: Add tests once parameter inference is supported
## Invalid expressions
The expressions in these string annotations aren't valid expressions in this context but we
shouldn't panic.
```py
a: "1 or 2"
b: "(x := 1)"
c: "1 + 2"
d: "lambda x: x"
e: "x if True else y"
f: "{'a': 1, 'b': 2}"
g: "{1, 2}"
h: "[i for i in range(5)]"
i: "{i for i in range(5)}"
j: "{i: i for i in range(5)}"
k: "(i for i in range(5))"
l: "await 1"
# error: [forward-annotation-syntax-error]
m: "yield 1"
# error: [forward-annotation-syntax-error]
n: "yield from 1"
o: "1 < 2"
p: "call()"
r: "[1, 2]"
s: "(1, 2)"
```

View File

@@ -22,3 +22,22 @@ reveal_type(1 if None else 2) # revealed: Literal[2]
reveal_type(1 if "" else 2) # revealed: Literal[2]
reveal_type(1 if 0 else 2) # revealed: Literal[2]
```
## Leaked Narrowing Constraint
(issue #14588)
The test inside an if expression should not affect code outside of the expression.
```py
def bool_instance() -> bool:
return True
x: Literal[42, "hello"] = 42 if bool_instance() else "hello"
reveal_type(x) # revealed: Literal[42] | Literal["hello"]
_ = ... if isinstance(x, str) else ...
reveal_type(x) # revealed: Literal[42] | Literal["hello"]
```

View File

@@ -60,52 +60,20 @@ reveal_type(S) # revealed: Literal[S]
## Type params
A PEP695 type variable defines a value of type `typing.TypeVar` with attributes `__name__`,
`__bounds__`, `__constraints__`, and `__default__` (the latter three all lazily evaluated):
A PEP695 type variable defines a value of type `typing.TypeVar`.
```py
def f[T, U: A, V: (A, B), W = A, X: A = A1]():
def f[T]():
reveal_type(T) # revealed: T
reveal_type(T.__name__) # revealed: Literal["T"]
reveal_type(T.__bound__) # revealed: None
reveal_type(T.__constraints__) # revealed: tuple[()]
reveal_type(T.__default__) # revealed: NoDefault
reveal_type(U) # revealed: U
reveal_type(U.__name__) # revealed: Literal["U"]
reveal_type(U.__bound__) # revealed: type[A]
reveal_type(U.__constraints__) # revealed: tuple[()]
reveal_type(U.__default__) # revealed: NoDefault
reveal_type(V) # revealed: V
reveal_type(V.__name__) # revealed: Literal["V"]
reveal_type(V.__bound__) # revealed: None
reveal_type(V.__constraints__) # revealed: tuple[type[A], type[B]]
reveal_type(V.__default__) # revealed: NoDefault
reveal_type(W) # revealed: W
reveal_type(W.__name__) # revealed: Literal["W"]
reveal_type(W.__bound__) # revealed: None
reveal_type(W.__constraints__) # revealed: tuple[()]
reveal_type(W.__default__) # revealed: type[A]
reveal_type(X) # revealed: X
reveal_type(X.__name__) # revealed: Literal["X"]
reveal_type(X.__bound__) # revealed: type[A]
reveal_type(X.__constraints__) # revealed: tuple[()]
reveal_type(X.__default__) # revealed: type[A1]
class A: ...
class B: ...
class A1(A): ...
```
## Minimum two constraints
A typevar with less than two constraints emits a diagnostic and is treated as unconstrained:
A typevar with less than two constraints emits a diagnostic:
```py
# error: [invalid-typevar-constraints] "TypeVar must have at least two constrained types"
def f[T: (int,)]():
reveal_type(T.__constraints__) # revealed: tuple[()]
pass
```

View File

@@ -52,3 +52,29 @@ else:
reveal_type(x) # revealed: Literal[2, 3]
reveal_type(y) # revealed: Literal[1, 2, 4]
```
## Nested while loops
```py
def flag() -> bool:
return True
x = 1
while flag():
x = 2
while flag():
x = 3
if flag():
break
else:
x = 4
if flag():
break
else:
x = 5
reveal_type(x) # revealed: Literal[3, 4, 5]
```

View File

@@ -256,7 +256,7 @@ class O: ...
class X(O): ...
class Y(O): ...
if bool():
if returns_bool():
foo = Y
else:
foo = object

View File

@@ -0,0 +1,32 @@
## Narrowing for `bool(..)` checks
```py
def flag() -> bool: ...
x = 1 if flag() else None
# valid invocation, positive
reveal_type(x) # revealed: Literal[1] | None
if bool(x is not None):
reveal_type(x) # revealed: Literal[1]
# valid invocation, negative
reveal_type(x) # revealed: Literal[1] | None
if not bool(x is not None):
reveal_type(x) # revealed: None
# no args/narrowing
reveal_type(x) # revealed: Literal[1] | None
if not bool():
reveal_type(x) # revealed: Literal[1] | None
# invalid invocation, too many positional args
reveal_type(x) # revealed: Literal[1] | None
if bool(x is not None, 5): # TODO diagnostic
reveal_type(x) # revealed: Literal[1] | None
# invalid invocation, too many kwargs
reveal_type(x) # revealed: Literal[1] | None
if bool(x is not None, y=5): # TODO diagnostic
reveal_type(x) # revealed: Literal[1] | None
```

View File

@@ -0,0 +1,64 @@
# Consolidating narrowed types after if statement
## After if-else statements, narrowing has no effect if the variable is not mutated in any branch
```py
def optional_int() -> int | None: ...
x = optional_int()
if x is None:
pass
else:
pass
reveal_type(x) # revealed: int | None
```
## Narrowing can have a persistent effect if the variable is mutated in one branch
```py
def optional_int() -> int | None: ...
x = optional_int()
if x is None:
x = 10
else:
pass
reveal_type(x) # revealed: int
```
## An if statement without an explicit `else` branch is equivalent to one with a no-op `else` branch
```py
def optional_int() -> int | None: ...
x = optional_int()
y = optional_int()
if x is None:
x = 0
if y is None:
pass
reveal_type(x) # revealed: int
reveal_type(y) # revealed: int | None
```
## An if-elif without an explicit else branch is equivalent to one with an empty else branch
```py
def optional_int() -> int | None: ...
x = optional_int()
if x is None:
x = 0
elif x > 50:
x = 50
reveal_type(x) # revealed: int
```

View File

@@ -21,10 +21,11 @@ reveal_type(Identity[0]) # revealed: str
## Class getitem union
```py
flag = True
def bool_instance() -> bool:
return True
class UnionClassGetItem:
if flag:
if bool_instance():
def __class_getitem__(cls, item: int) -> str:
return item
@@ -59,9 +60,10 @@ reveal_type(x[0]) # revealed: str | int
## Class getitem with unbound method union
```py
flag = True
def bool_instance() -> bool:
return True
if flag:
if bool_instance():
class Spam:
def __class_getitem__(self, x: int) -> str:
return "foo"
@@ -77,9 +79,10 @@ reveal_type(Spam[42])
## TODO: Class getitem non-class union
```py
flag = True
def bool_instance() -> bool:
return True
if flag:
if bool_instance():
class Eggs:
def __class_getitem__(self, x: int) -> str:
return "foo"

View File

@@ -30,10 +30,11 @@ reveal_type(Identity()[0]) # revealed: int
## Getitem union
```py
flag = True
def bool_instance() -> bool:
return True
class Identity:
if flag:
if bool_instance():
def __getitem__(self, index: int) -> int:
return index

View File

@@ -416,7 +416,7 @@ impl<'db> Iterator for SearchPathIterator<'db> {
}
}
impl<'db> FusedIterator for SearchPathIterator<'db> {}
impl FusedIterator for SearchPathIterator<'_> {}
/// Represents a single `.pth` file in a `site-packages` directory.
/// One or more lines in a `.pth` file may be a (relative or absolute)

View File

@@ -36,12 +36,25 @@ use super::definition::{
mod except_handlers;
/// Are we in a state where a `break` statement is allowed?
#[derive(Clone, Copy, Debug)]
enum LoopState {
InLoop,
NotInLoop,
}
impl LoopState {
fn is_inside(self) -> bool {
matches!(self, LoopState::InLoop)
}
}
pub(super) struct SemanticIndexBuilder<'db> {
// Builder state
db: &'db dyn Db,
file: File,
module: &'db ParsedModule,
scope_stack: Vec<FileScopeId>,
scope_stack: Vec<(FileScopeId, LoopState)>,
/// The assignments we're currently visiting, with
/// the most recent visit at the end of the Vec
current_assignments: Vec<CurrentAssignment<'db>>,
@@ -103,9 +116,24 @@ impl<'db> SemanticIndexBuilder<'db> {
*self
.scope_stack
.last()
.map(|(scope, _)| scope)
.expect("Always to have a root scope")
}
fn loop_state(&self) -> LoopState {
self.scope_stack
.last()
.expect("Always to have a root scope")
.1
}
fn set_inside_loop(&mut self, state: LoopState) {
self.scope_stack
.last_mut()
.expect("Always to have a root scope")
.1 = state;
}
fn push_scope(&mut self, node: NodeWithScopeRef) {
let parent = self.current_scope();
self.push_scope_with_parent(node, Some(parent));
@@ -136,11 +164,11 @@ impl<'db> SemanticIndexBuilder<'db> {
debug_assert_eq!(ast_id_scope, file_scope_id);
self.scope_stack.push(file_scope_id);
self.scope_stack.push((file_scope_id, LoopState::NotInLoop));
}
fn pop_scope(&mut self) -> FileScopeId {
let id = self.scope_stack.pop().expect("Root scope to be present");
let (id, _) = self.scope_stack.pop().expect("Root scope to be present");
let children_end = self.scopes.next_index();
let scope = &mut self.scopes[id];
scope.descendents = scope.descendents.start..children_end;
@@ -741,7 +769,22 @@ where
let mut constraints = vec![constraint];
self.visit_body(&node.body);
let mut post_clauses: Vec<FlowSnapshot> = vec![];
for clause in &node.elif_else_clauses {
let elif_else_clauses = node
.elif_else_clauses
.iter()
.map(|clause| (clause.test.as_ref(), clause.body.as_slice()));
let has_else = node
.elif_else_clauses
.last()
.is_some_and(|clause| clause.test.is_none());
let elif_else_clauses = elif_else_clauses.chain(if has_else {
// if there's an `else` clause already, we don't need to add another
None
} else {
// if there's no `else` branch, we should add a no-op `else` branch
Some((None, Default::default()))
});
for (clause_test, clause_body) in elif_else_clauses {
// snapshot after every block except the last; the last one will just become
// the state that we merge the other snapshots into
post_clauses.push(self.flow_snapshot());
@@ -751,24 +794,15 @@ where
for constraint in &constraints {
self.record_negated_constraint(*constraint);
}
if let Some(elif_test) = &clause.test {
if let Some(elif_test) = clause_test {
self.visit_expr(elif_test);
constraints.push(self.record_expression_constraint(elif_test));
}
self.visit_body(&clause.body);
self.visit_body(clause_body);
}
for post_clause_state in post_clauses {
self.flow_merge(post_clause_state);
}
let has_else = node
.elif_else_clauses
.last()
.is_some_and(|clause| clause.test.is_none());
if !has_else {
// if there's no else clause, then it's possible we took none of the branches,
// and the pre_if state can reach here
self.flow_merge(pre_if);
}
}
ast::Stmt::While(ast::StmtWhile {
test,
@@ -785,7 +819,10 @@ where
// TODO: definitions created inside the body should be fully visible
// to other statements/expressions inside the body --Alex/Carl
let outer_loop_state = self.loop_state();
self.set_inside_loop(LoopState::InLoop);
self.visit_body(body);
self.set_inside_loop(outer_loop_state);
// Get the break states from the body of this loop, and restore the saved outer
// ones.
@@ -824,7 +861,9 @@ where
self.visit_body(body);
}
ast::Stmt::Break(_) => {
self.loop_break_states.push(self.flow_snapshot());
if self.loop_state().is_inside() {
self.loop_break_states.push(self.flow_snapshot());
}
}
ast::Stmt::For(
@@ -851,7 +890,10 @@ where
// TODO: Definitions created by loop variables
// (and definitions created inside the body)
// are fully visible to other statements/expressions inside the body --Alex/Carl
let outer_loop_state = self.loop_state();
self.set_inside_loop(LoopState::InLoop);
self.visit_body(body);
self.set_inside_loop(outer_loop_state);
let break_states =
std::mem::replace(&mut self.loop_break_states, saved_break_states);
@@ -1153,8 +1195,8 @@ where
// AST inspection, so we can't simplify here, need to record test expression for
// later checking)
self.visit_expr(test);
let constraint = self.record_expression_constraint(test);
let pre_if = self.flow_snapshot();
let constraint = self.record_expression_constraint(test);
self.visit_expr(body);
let post_body = self.flow_snapshot();
self.flow_restore(pre_if);

View File

@@ -400,7 +400,7 @@ pub(crate) struct ConstraintsIterator<'map, 'db> {
constraint_ids: ConstraintIdIterator<'map>,
}
impl<'map, 'db> Iterator for ConstraintsIterator<'map, 'db> {
impl<'db> Iterator for ConstraintsIterator<'_, 'db> {
type Item = Constraint<'db>;
fn next(&mut self) -> Option<Self::Item> {
@@ -424,7 +424,7 @@ impl DeclarationsIterator<'_, '_> {
}
}
impl<'map, 'db> Iterator for DeclarationsIterator<'map, 'db> {
impl<'db> Iterator for DeclarationsIterator<'_, 'db> {
type Item = Definition<'db>;
fn next(&mut self) -> Option<Self::Item> {

View File

@@ -401,7 +401,7 @@ pub(super) struct DeclarationIdIterator<'a> {
inner: DeclarationsIterator<'a>,
}
impl<'a> Iterator for DeclarationIdIterator<'a> {
impl Iterator for DeclarationIdIterator<'_> {
type Item = ScopedDefinitionId;
fn next(&mut self) -> Option<Self::Item> {

View File

@@ -537,6 +537,19 @@ impl<'db> Type<'db> {
.expect("Expected a Type::IntLiteral variant")
}
pub const fn into_known_instance(self) -> Option<KnownInstanceType<'db>> {
match self {
Type::KnownInstance(known_instance) => Some(known_instance),
_ => None,
}
}
#[track_caller]
pub fn expect_known_instance(self) -> KnownInstanceType<'db> {
self.into_known_instance()
.expect("Expected a Type::KnownInstance variant")
}
pub const fn is_boolean_literal(&self) -> bool {
matches!(self, Type::BooleanLiteral(..))
}
@@ -1390,7 +1403,7 @@ impl<'db> Type<'db> {
// `Any` is callable, and its return type is also `Any`.
Type::Any => CallOutcome::callable(Type::Any),
Type::Todo(_) => CallOutcome::callable(todo_type!()),
Type::Todo(_) => CallOutcome::callable(todo_type!("call todo")),
Type::Unknown => CallOutcome::callable(Type::Unknown),
@@ -1540,6 +1553,10 @@ impl<'db> Type<'db> {
// TODO map this to a new `Type::TypeVar` variant
Type::KnownInstance(KnownInstanceType::TypeVar(_)) => *self,
Type::KnownInstance(KnownInstanceType::TypeAliasType(alias)) => alias.value_ty(db),
Type::KnownInstance(KnownInstanceType::Never | KnownInstanceType::NoReturn) => {
Type::Never
}
Type::KnownInstance(KnownInstanceType::LiteralString) => Type::LiteralString,
_ => todo_type!(),
}
}
@@ -1872,10 +1889,16 @@ impl<'db> KnownClass {
pub enum KnownInstanceType<'db> {
/// The symbol `typing.Literal` (which can also be found as `typing_extensions.Literal`)
Literal,
/// The symbol `typing.LiteralString` (which can also be found as `typing_extensions.LiteralString`)
LiteralString,
/// The symbol `typing.Optional` (which can also be found as `typing_extensions.Optional`)
Optional,
/// The symbol `typing.Union` (which can also be found as `typing_extensions.Union`)
Union,
/// The symbol `typing.NoReturn` (which can also be found as `typing_extensions.NoReturn`)
NoReturn,
/// The symbol `typing.Never` available since 3.11 (which can also be found as `typing_extensions.Never`)
Never,
/// A single instance of `typing.TypeVar`
TypeVar(TypeVarInstance<'db>),
/// A single instance of `typing.TypeAliasType` (PEP 695 type alias)
@@ -1886,11 +1909,14 @@ pub enum KnownInstanceType<'db> {
impl<'db> KnownInstanceType<'db> {
pub const fn as_str(self) -> &'static str {
match self {
KnownInstanceType::Literal => "Literal",
KnownInstanceType::Optional => "Optional",
KnownInstanceType::Union => "Union",
KnownInstanceType::TypeVar(_) => "TypeVar",
KnownInstanceType::TypeAliasType(_) => "TypeAliasType",
Self::Literal => "Literal",
Self::LiteralString => "LiteralString",
Self::Optional => "Optional",
Self::Union => "Union",
Self::TypeVar(_) => "TypeVar",
Self::NoReturn => "NoReturn",
Self::Never => "Never",
Self::TypeAliasType(_) => "TypeAliasType",
}
}
@@ -1898,9 +1924,12 @@ impl<'db> KnownInstanceType<'db> {
pub const fn bool(self) -> Truthiness {
match self {
Self::Literal
| Self::LiteralString
| Self::Optional
| Self::TypeVar(_)
| Self::Union
| Self::NoReturn
| Self::Never
| Self::TypeAliasType(_) => Truthiness::AlwaysTrue,
}
}
@@ -1909,8 +1938,11 @@ impl<'db> KnownInstanceType<'db> {
pub fn repr(self, db: &'db dyn Db) -> &'db str {
match self {
Self::Literal => "typing.Literal",
Self::LiteralString => "typing.LiteralString",
Self::Optional => "typing.Optional",
Self::Union => "typing.Union",
Self::NoReturn => "typing.NoReturn",
Self::Never => "typing.Never",
Self::TypeVar(typevar) => typevar.name(db),
Self::TypeAliasType(_) => "typing.TypeAliasType",
}
@@ -1920,8 +1952,11 @@ impl<'db> KnownInstanceType<'db> {
pub const fn class(self) -> KnownClass {
match self {
Self::Literal => KnownClass::SpecialForm,
Self::LiteralString => KnownClass::SpecialForm,
Self::Optional => KnownClass::SpecialForm,
Self::Union => KnownClass::SpecialForm,
Self::NoReturn => KnownClass::SpecialForm,
Self::Never => KnownClass::SpecialForm,
Self::TypeVar(_) => KnownClass::TypeVar,
Self::TypeAliasType(_) => KnownClass::TypeAliasType,
}
@@ -1942,8 +1977,11 @@ impl<'db> KnownInstanceType<'db> {
}
match (module.name().as_str(), instance_name) {
("typing" | "typing_extensions", "Literal") => Some(Self::Literal),
("typing" | "typing_extensions", "LiteralString") => Some(Self::LiteralString),
("typing" | "typing_extensions", "Optional") => Some(Self::Optional),
("typing" | "typing_extensions", "Union") => Some(Self::Union),
("typing" | "typing_extensions", "NoReturn") => Some(Self::NoReturn),
("typing" | "typing_extensions", "Never") => Some(Self::Never),
_ => None,
}
}
@@ -1951,23 +1989,6 @@ impl<'db> KnownInstanceType<'db> {
fn member(self, db: &'db dyn Db, name: &str) -> Symbol<'db> {
let ty = match (self, name) {
(Self::TypeVar(typevar), "__name__") => Type::string_literal(db, typevar.name(db)),
(Self::TypeVar(typevar), "__bound__") => typevar
.upper_bound(db)
.map(|ty| ty.to_meta_type(db))
.unwrap_or_else(|| KnownClass::NoneType.to_instance(db)),
(Self::TypeVar(typevar), "__constraints__") => {
let tuple_elements: Vec<Type<'db>> = typevar
.constraints(db)
.unwrap_or_default()
.iter()
.map(|ty| ty.to_meta_type(db))
.collect();
Type::tuple(db, &tuple_elements)
}
(Self::TypeVar(typevar), "__default__") => typevar
.default_ty(db)
.map(|ty| ty.to_meta_type(db))
.unwrap_or_else(|| KnownClass::NoDefaultType.to_instance(db)),
(Self::TypeAliasType(alias), "__name__") => Type::string_literal(db, alias.name(db)),
_ => return self.instance_fallback(db).member(db, name),
};
@@ -2000,6 +2021,7 @@ pub struct TypeVarInstance<'db> {
}
impl<'db> TypeVarInstance<'db> {
#[allow(unused)]
pub(crate) fn upper_bound(self, db: &'db dyn Db) -> Option<Type<'db>> {
if let Some(TypeVarBoundOrConstraints::UpperBound(ty)) = self.bound_or_constraints(db) {
Some(ty)
@@ -2008,7 +2030,8 @@ impl<'db> TypeVarInstance<'db> {
}
}
pub(crate) fn constraints(self, db: &'db dyn Db) -> Option<&[Type<'db>]> {
#[allow(unused)]
pub(crate) fn constraints(self, db: &'db dyn Db) -> Option<&'db [Type<'db>]> {
if let Some(TypeVarBoundOrConstraints::Constraints(tuple)) = self.bound_or_constraints(db) {
Some(tuple.elements(db))
} else {
@@ -2552,7 +2575,7 @@ impl<'db> Class<'db> {
///
/// Were this not a salsa query, then the calling query
/// would depend on the class's AST and rerun for every change in that file.
fn explicit_bases(self, db: &'db dyn Db) -> &[Type<'db>] {
fn explicit_bases(self, db: &'db dyn Db) -> &'db [Type<'db>] {
self.explicit_bases_query(db)
}
@@ -2980,7 +3003,7 @@ pub struct SliceLiteralType<'db> {
step: Option<i32>,
}
impl<'db> SliceLiteralType<'db> {
impl SliceLiteralType<'_> {
fn as_tuple(self, db: &dyn Db) -> (Option<i32>, Option<i32>, Option<i32>) {
(self.start(db), self.stop(db), self.step(db))
}

View File

@@ -289,7 +289,7 @@ struct DisplayMaybeNegatedType<'db> {
negated: bool,
}
impl<'db> Display for DisplayMaybeNegatedType<'db> {
impl Display for DisplayMaybeNegatedType<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.negated {
f.write_str("~")?;
@@ -319,7 +319,7 @@ pub(crate) struct DisplayTypeArray<'b, 'db> {
db: &'db dyn Db,
}
impl<'db> Display for DisplayTypeArray<'_, 'db> {
impl Display for DisplayTypeArray<'_, '_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.join(", ")
.entries(self.types.iter().map(|ty| ty.display(self.db)))

View File

@@ -4229,6 +4229,7 @@ impl<'db> TypeInferenceBuilder<'db> {
"annotation-f-string",
format_args!("Type expressions cannot use f-strings"),
);
self.infer_fstring_expression(fstring);
Type::Unknown
}
@@ -4374,6 +4375,10 @@ impl<'db> TypeInferenceBuilder<'db> {
todo_type!()
}
// Avoid inferring the types of invalid type expressions that have been parsed from a
// string annotation, as they are not present in the semantic index.
_ if self.deferred_state.in_string_annotation() => Type::Unknown,
// Forms which are invalid in the context of annotation expressions: we infer their
// nested expressions as normal expressions, but the type of the top-level expression is
// always `Type::Unknown` in these cases.
@@ -4457,7 +4462,6 @@ impl<'db> TypeInferenceBuilder<'db> {
self.infer_slice_expression(slice);
Type::Unknown
}
ast::Expr::IpyEscapeCommand(_) => todo!("Implement Ipy escape command support"),
}
}
@@ -4572,7 +4576,7 @@ impl<'db> TypeInferenceBuilder<'db> {
match value_ty {
Type::KnownInstance(known_instance) => {
self.infer_parameterized_known_instance_type_expression(known_instance, slice)
self.infer_parameterized_known_instance_type_expression(subscript, known_instance)
}
_ => {
self.infer_type_expression(slice);
@@ -4583,9 +4587,10 @@ impl<'db> TypeInferenceBuilder<'db> {
fn infer_parameterized_known_instance_type_expression(
&mut self,
subscript: &ast::ExprSubscript,
known_instance: KnownInstanceType,
parameters: &ast::Expr,
) -> Type<'db> {
let parameters = &*subscript.slice;
match known_instance {
KnownInstanceType::Literal => match self.infer_literal_parameter_type(parameters) {
Ok(ty) => ty,
@@ -4626,6 +4631,28 @@ impl<'db> TypeInferenceBuilder<'db> {
self.infer_type_expression(parameters);
todo_type!("generic type alias")
}
KnownInstanceType::NoReturn | KnownInstanceType::Never => {
self.diagnostics.add(
subscript.into(),
"invalid-type-parameter",
format_args!(
"Type `{}` expected no type parameter",
known_instance.repr(self.db)
),
);
Type::Unknown
}
KnownInstanceType::LiteralString => {
self.diagnostics.add(
subscript.into(),
"invalid-type-parameter",
format_args!(
"Type `{}` expected no type parameter. Did you mean to use `Literal[...]` instead?",
known_instance.repr(self.db)
),
);
Type::Unknown
}
}
}
@@ -5970,7 +5997,11 @@ mod tests {
"src/a.py",
&["foo", "<listcomp>"],
"x",
"@Todo(async iterables/iterators)",
if cfg!(debug_assertions) {
"@Todo(async iterables/iterators)"
} else {
"@Todo"
},
);
Ok(())
@@ -6000,7 +6031,11 @@ mod tests {
"src/a.py",
&["foo", "<listcomp>"],
"x",
"@Todo(async iterables/iterators)",
if cfg!(debug_assertions) {
"@Todo(async iterables/iterators)"
} else {
"@Todo"
},
);
Ok(())
@@ -6035,6 +6070,72 @@ mod tests {
);
}
#[test]
fn pep695_type_params() {
let mut db = setup_db();
db.write_dedented(
"src/a.py",
"
def f[T, U: A, V: (A, B), W = A, X: A = A1, Y: (int,)]():
pass
class A: ...
class B: ...
class A1(A): ...
",
)
.unwrap();
let check_typevar = |var: &'static str,
upper_bound: Option<&'static str>,
constraints: Option<&[&'static str]>,
default: Option<&'static str>| {
let var_ty = get_symbol(&db, "src/a.py", &["f"], var).expect_type();
assert_eq!(var_ty.display(&db).to_string(), var);
let expected_name_ty = format!(r#"Literal["{var}"]"#);
let name_ty = var_ty.member(&db, "__name__").expect_type();
assert_eq!(name_ty.display(&db).to_string(), expected_name_ty);
let KnownInstanceType::TypeVar(typevar) = var_ty.expect_known_instance() else {
panic!("expected TypeVar");
};
assert_eq!(
typevar
.upper_bound(&db)
.map(|ty| ty.display(&db).to_string()),
upper_bound.map(std::borrow::ToOwned::to_owned)
);
assert_eq!(
typevar.constraints(&db).map(|tys| tys
.iter()
.map(|ty| ty.display(&db).to_string())
.collect::<Vec<_>>()),
constraints.map(|strings| strings
.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<_>>())
);
assert_eq!(
typevar
.default_ty(&db)
.map(|ty| ty.display(&db).to_string()),
default.map(std::borrow::ToOwned::to_owned)
);
};
check_typevar("T", None, None, None);
check_typevar("U", Some("A"), None, None);
check_typevar("V", None, Some(&["A", "B"]), None);
check_typevar("W", None, None, Some("A"));
check_typevar("X", Some("A"), None, Some("A1"));
// a typevar with less than two constraints is treated as unconstrained
check_typevar("Y", None, None, None);
}
// Incremental inference tests
fn first_public_binding<'db>(db: &'db TestDb, file: File, name: &str) -> Definition<'db> {

View File

@@ -374,7 +374,10 @@ impl<'db> ClassBase<'db> {
KnownInstanceType::TypeVar(_)
| KnownInstanceType::TypeAliasType(_)
| KnownInstanceType::Literal
| KnownInstanceType::LiteralString
| KnownInstanceType::Union
| KnownInstanceType::NoReturn
| KnownInstanceType::Never
| KnownInstanceType::Optional => None,
},
}

View File

@@ -54,6 +54,7 @@ pub(crate) fn narrowing_constraint<'db>(
}
}
#[allow(clippy::ref_option)]
#[salsa::tracked(return_ref)]
fn all_narrowing_constraints_for_pattern<'db>(
db: &'db dyn Db,
@@ -62,6 +63,7 @@ fn all_narrowing_constraints_for_pattern<'db>(
NarrowingConstraintsBuilder::new(db, ConstraintNode::Pattern(pattern), true).finish()
}
#[allow(clippy::ref_option)]
#[salsa::tracked(return_ref)]
fn all_narrowing_constraints_for_expression<'db>(
db: &'db dyn Db,
@@ -70,6 +72,7 @@ fn all_narrowing_constraints_for_expression<'db>(
NarrowingConstraintsBuilder::new(db, ConstraintNode::Expression(expression), true).finish()
}
#[allow(clippy::ref_option)]
#[salsa::tracked(return_ref)]
fn all_negative_narrowing_constraints_for_expression<'db>(
db: &'db dyn Db,
@@ -291,8 +294,15 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
.chain(comparators)
.tuple_windows::<(&ruff_python_ast::Expr, &ruff_python_ast::Expr)>();
let mut constraints = NarrowingConstraints::default();
let mut last_rhs_ty: Option<Type> = None;
for (op, (left, right)) in std::iter::zip(&**ops, comparator_tuples) {
let lhs_ty = last_rhs_ty.unwrap_or_else(|| {
inference.expression_ty(left.scoped_expression_id(self.db, scope))
});
let rhs_ty = inference.expression_ty(right.scoped_expression_id(self.db, scope));
last_rhs_ty = Some(rhs_ty);
match left {
ast::Expr::Name(ast::ExprName {
@@ -327,6 +337,9 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
constraints.insert(symbol, ty);
}
}
ast::CmpOp::Eq if lhs_ty.is_literal_string() => {
constraints.insert(symbol, rhs_ty);
}
_ => {
// TODO other comparison types
}
@@ -385,46 +398,58 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
let scope = self.scope();
let inference = infer_expression_types(self.db, expression);
let callable_ty =
inference.expression_ty(expr_call.func.scoped_expression_id(self.db, scope));
// TODO: add support for PEP 604 union types on the right hand side of `isinstance`
// and `issubclass`, for example `isinstance(x, str | (int | float))`.
match inference
.expression_ty(expr_call.func.scoped_expression_id(self.db, scope))
.into_function_literal()
.and_then(|f| f.known(self.db))
.and_then(KnownFunction::constraint_function)
{
Some(function) if expr_call.arguments.keywords.is_empty() => {
if let [ast::Expr::Name(ast::ExprName { id, .. }), class_info] =
match callable_ty {
Type::FunctionLiteral(function_type) if expr_call.arguments.keywords.is_empty() => {
let function = function_type
.known(self.db)
.and_then(KnownFunction::constraint_function)?;
let [ast::Expr::Name(ast::ExprName { id, .. }), class_info] =
&*expr_call.arguments.args
{
let symbol = self.symbols().symbol_id_by_name(id).unwrap();
else {
return None;
};
let class_info_ty =
inference.expression_ty(class_info.scoped_expression_id(self.db, scope));
let symbol = self.symbols().symbol_id_by_name(id).unwrap();
let to_constraint = match function {
KnownConstraintFunction::IsInstance => {
|class_literal: ClassLiteralType<'db>| {
Type::instance(class_literal.class)
}
let class_info_ty =
inference.expression_ty(class_info.scoped_expression_id(self.db, scope));
let to_constraint = match function {
KnownConstraintFunction::IsInstance => {
|class_literal: ClassLiteralType<'db>| Type::instance(class_literal.class)
}
KnownConstraintFunction::IsSubclass => {
|class_literal: ClassLiteralType<'db>| {
Type::subclass_of(class_literal.class)
}
KnownConstraintFunction::IsSubclass => {
|class_literal: ClassLiteralType<'db>| {
Type::subclass_of(class_literal.class)
}
}
};
}
};
generate_classinfo_constraint(self.db, &class_info_ty, to_constraint).map(
|constraint| {
let mut constraints = NarrowingConstraints::default();
constraints.insert(symbol, constraint.negate_if(self.db, !is_positive));
constraints
},
)
} else {
None
}
generate_classinfo_constraint(self.db, &class_info_ty, to_constraint).map(
|constraint| {
let mut constraints = NarrowingConstraints::default();
constraints.insert(symbol, constraint.negate_if(self.db, !is_positive));
constraints
},
)
}
// for the expression `bool(E)`, we further narrow the type based on `E`
Type::ClassLiteral(class_type)
if expr_call.arguments.args.len() == 1
&& expr_call.arguments.keywords.is_empty()
&& class_type.class.is_known(self.db, KnownClass::Bool) =>
{
self.evaluate_expression_node_constraint(
&expr_call.arguments.args[0],
expression,
is_positive,
)
}
_ => None,
}

View File

@@ -1,7 +1,6 @@
use std::ffi::OsStr;
use std::path::Path;
use camino::Utf8Path;
use dir_test::{dir_test, Fixture};
use std::path::Path;
/// See `crates/red_knot_test/README.md` for documentation on these tests.
#[dir_test(
@@ -10,16 +9,46 @@ use dir_test::{dir_test, Fixture};
)]
#[allow(clippy::needless_pass_by_value)]
fn mdtest(fixture: Fixture<&str>) {
let fixture_path = Path::new(fixture.path());
let fixture_path = Utf8Path::new(fixture.path());
let crate_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let workspace_root = crate_dir.parent().and_then(Path::parent).unwrap();
let workspace_root = crate_dir.ancestors().nth(2).unwrap();
let long_title = fixture_path
.strip_prefix(workspace_root)
.unwrap()
.to_str()
.unwrap();
let short_title = fixture_path.file_name().and_then(OsStr::to_str).unwrap();
let long_title = fixture_path.strip_prefix(workspace_root).unwrap();
let short_title = fixture_path.file_name().unwrap();
red_knot_test::run(fixture_path, long_title, short_title);
let test_name = test_name("mdtest", fixture_path);
red_knot_test::run(fixture_path, long_title.as_str(), short_title, &test_name);
}
/// Constructs the test name used for individual markdown files
///
/// This code is copied from <https://github.com/fe-lang/dir-test/blob/1c0f41c480a3490bc2653a043ff6e3f8085a1f47/macros/src/lib.rs#L104-L138>
/// and should be updated if they diverge
fn test_name(test_func_name: &str, fixture_path: &Utf8Path) -> String {
assert!(fixture_path.is_file());
let dir_path = format!("{}/resources/mdtest", std::env!("CARGO_MANIFEST_DIR"));
let rel_path = fixture_path.strip_prefix(dir_path).unwrap();
assert!(rel_path.is_relative());
let mut test_name = test_func_name.to_owned();
test_name.push_str("__");
for component in rel_path.parent().unwrap().components() {
let component = component
.as_str()
.replace(|c: char| c.is_ascii_punctuation(), "_");
test_name.push_str(&component);
test_name.push('_');
}
test_name.push_str(
&rel_path
.file_stem()
.unwrap()
.replace(|c: char| c.is_ascii_punctuation(), "_"),
);
test_name
}

View File

@@ -26,7 +26,7 @@ pub(crate) struct Requester<'s> {
response_handlers: FxHashMap<lsp_server::RequestId, ResponseBuilder<'s>>,
}
impl<'s> Client<'s> {
impl Client<'_> {
pub(super) fn new(sender: ClientSender) -> Self {
Self {
notifier: Notifier(sender.clone()),

View File

@@ -20,6 +20,7 @@ ruff_source_file = { workspace = true }
ruff_text_size = { workspace = true }
anyhow = { workspace = true }
camino = { workspace = true }
colored = { workspace = true }
memchr = { workspace = true }
regex = { workspace = true }

View File

@@ -184,8 +184,11 @@ The tests are run independently, in independent in-memory file systems and with
[Salsa](https://github.com/salsa-rs/salsa) databases. This means that each is a from-scratch run of
the type checker, with no data persisting from any previous test.
Due to `cargo test` limitations, an entire test suite (Markdown file) is run as a single Rust test,
so it's not possible to select individual tests within it to run.
It is possible to filter to individual tests within a single markdown file using the
`MDTEST_TEST_FILTER` environment variable. This variable will match any tests which contain the
value as a case-sensitive substring in its name. An example test name is
`unpacking.md - Unpacking - Tuple - Multiple assignment`, which contains the name of the markdown
file and its parent headers joined together with hyphens.
## Structured test suites

View File

@@ -1,3 +1,4 @@
use camino::Utf8Path;
use colored::Colorize;
use parser as test_parser;
use red_knot_python_semantic::types::check_types;
@@ -7,7 +8,6 @@ use ruff_db::parsed::parsed_module;
use ruff_db::system::{DbWithTestSystem, SystemPathBuf};
use ruff_source_file::LineIndex;
use ruff_text_size::TextSize;
use std::path::Path;
mod assertion;
mod db;
@@ -15,23 +15,30 @@ mod diagnostic;
mod matcher;
mod parser;
const MDTEST_TEST_FILTER: &str = "MDTEST_TEST_FILTER";
/// Run `path` as a markdown test suite with given `title`.
///
/// Panic on test failure, and print failure details.
#[allow(clippy::print_stdout)]
pub fn run(path: &Path, long_title: &str, short_title: &str) {
pub fn run(path: &Utf8Path, long_title: &str, short_title: &str, test_name: &str) {
let source = std::fs::read_to_string(path).unwrap();
let suite = match test_parser::parse(short_title, &source) {
Ok(suite) => suite,
Err(err) => {
panic!("Error parsing `{}`: {err}", path.to_str().unwrap())
panic!("Error parsing `{path}`: {err}")
}
};
let mut db = db::Db::setup(SystemPathBuf::from("/src"));
let filter = std::env::var(MDTEST_TEST_FILTER).ok();
let mut any_failures = false;
for test in suite.tests() {
if filter.as_ref().is_some_and(|f| !test.name().contains(f)) {
continue;
}
// Remove all files so that the db is in a "fresh" state.
db.memory_file_system().remove_all();
Files::sync_all(&mut db);
@@ -54,6 +61,15 @@ pub fn run(path: &Path, long_title: &str, short_title: &str) {
}
}
}
println!(
"\nTo rerun this specific test, set the environment variable: {MDTEST_TEST_FILTER}=\"{}\"",
test.name()
);
println!(
"{MDTEST_TEST_FILTER}=\"{}\" cargo test -p red_knot_python_semantic --test mdtest -- {test_name}",
test.name()
);
}
}

View File

@@ -180,6 +180,16 @@ where
}
}
/// Discard `@Todo`-type metadata from expected types, which is not available
/// when running in release mode.
#[cfg(not(debug_assertions))]
fn discard_todo_metadata(ty: &str) -> std::borrow::Cow<'_, str> {
static TODO_METADATA_REGEX: std::sync::LazyLock<regex::Regex> =
std::sync::LazyLock::new(|| regex::Regex::new(r"@Todo\([^)]*\)").unwrap());
TODO_METADATA_REGEX.replace_all(ty, "@Todo")
}
struct Matcher {
line_index: LineIndex,
source: SourceText,
@@ -276,6 +286,9 @@ impl Matcher {
}
}
Assertion::Revealed(expected_type) => {
#[cfg(not(debug_assertions))]
let expected_type = discard_todo_metadata(&expected_type);
let mut matched_revealed_type = None;
let mut matched_undefined_reveal = None;
let expected_reveal_type_message = format!("Revealed type is `{expected_type}`");

View File

@@ -1 +1 @@
5052fa2f18db4493892e0f2775030683c9d06531
0a2da01946a406ede42e9c66f416a7e7758991d6

View File

@@ -33,6 +33,7 @@ _contextvars: 3.7-
_csv: 3.0-
_ctypes: 3.0-
_curses: 3.0-
_curses_panel: 3.0-
_dbm: 3.0-
_decimal: 3.3-
_dummy_thread: 3.0-3.8
@@ -40,6 +41,7 @@ _dummy_threading: 3.0-3.8
_frozen_importlib: 3.0-
_frozen_importlib_external: 3.5-
_gdbm: 3.0-
_hashlib: 3.0-
_heapq: 3.0-
_imp: 3.0-
_interpchannels: 3.13-
@@ -52,6 +54,7 @@ _lsprof: 3.0-
_lzma: 3.3-
_markupbase: 3.0-
_msi: 3.0-3.12
_multibytecodec: 3.0-
_operator: 3.4-
_osx_support: 3.0-
_posixsubprocess: 3.2-
@@ -139,6 +142,12 @@ doctest: 3.0-
dummy_threading: 3.0-3.8
email: 3.0-
encodings: 3.0-
encodings.cp1125: 3.4-
encodings.cp273: 3.4-
encodings.cp858: 3.2-
encodings.koi8_t: 3.5-
encodings.kz1048: 3.5-
encodings.mac_centeuro: 3.0-3.8
ensurepip: 3.0-
enum: 3.4-
errno: 3.0-

View File

@@ -2,10 +2,13 @@ import codecs
import sys
from _typeshed import ReadableBuffer
from collections.abc import Callable
from typing import Literal, overload
from typing import Literal, final, overload, type_check_only
from typing_extensions import TypeAlias
# This type is not exposed; it is defined in unicodeobject.c
# At runtime it calls itself builtins.EncodingMap
@final
@type_check_only
class _EncodingMap:
def size(self) -> int: ...

View File

@@ -73,6 +73,7 @@ _VT_co = TypeVar("_VT_co", covariant=True) # Value type covariant containers.
@final
class dict_keys(KeysView[_KT_co], Generic[_KT_co, _VT_co]): # undocumented
def __eq__(self, value: object, /) -> bool: ...
def __reversed__(self) -> Iterator[_KT_co]: ...
if sys.version_info >= (3, 13):
def isdisjoint(self, other: Iterable[_KT_co], /) -> bool: ...
if sys.version_info >= (3, 10):
@@ -81,6 +82,7 @@ class dict_keys(KeysView[_KT_co], Generic[_KT_co, _VT_co]): # undocumented
@final
class dict_values(ValuesView[_VT_co], Generic[_KT_co, _VT_co]): # undocumented
def __reversed__(self) -> Iterator[_VT_co]: ...
if sys.version_info >= (3, 10):
@property
def mapping(self) -> MappingProxyType[_KT_co, _VT_co]: ...
@@ -88,6 +90,7 @@ class dict_values(ValuesView[_VT_co], Generic[_KT_co, _VT_co]): # undocumented
@final
class dict_items(ItemsView[_KT_co, _VT_co]): # undocumented
def __eq__(self, value: object, /) -> bool: ...
def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ...
if sys.version_info >= (3, 13):
def isdisjoint(self, other: Iterable[tuple[_KT_co, _VT_co]], /) -> bool: ...
if sys.version_info >= (3, 10):

View File

@@ -1,9 +1,9 @@
import csv
import sys
from _typeshed import SupportsWrite
from collections.abc import Iterable, Iterator
from typing import Any, Final
from typing_extensions import TypeAlias
from collections.abc import Iterable
from typing import Any, Final, type_check_only
from typing_extensions import Self, TypeAlias
__version__: Final[str]
@@ -45,17 +45,47 @@ class Dialect:
strict: bool = False,
) -> None: ...
class _reader(Iterator[list[str]]):
@property
def dialect(self) -> Dialect: ...
line_num: int
def __next__(self) -> list[str]: ...
if sys.version_info >= (3, 10):
# This class calls itself _csv.reader.
class Reader:
@property
def dialect(self) -> Dialect: ...
line_num: int
def __iter__(self) -> Self: ...
def __next__(self) -> list[str]: ...
class _writer:
@property
def dialect(self) -> Dialect: ...
def writerow(self, row: Iterable[Any]) -> Any: ...
def writerows(self, rows: Iterable[Iterable[Any]]) -> None: ...
# This class calls itself _csv.writer.
class Writer:
@property
def dialect(self) -> Dialect: ...
if sys.version_info >= (3, 13):
def writerow(self, row: Iterable[Any], /) -> Any: ...
def writerows(self, rows: Iterable[Iterable[Any]], /) -> None: ...
else:
def writerow(self, row: Iterable[Any]) -> Any: ...
def writerows(self, rows: Iterable[Iterable[Any]]) -> None: ...
# For the return types below.
# These aliases can be removed when typeshed drops support for 3.9.
_reader = Reader
_writer = Writer
else:
# This class is not exposed. It calls itself _csv.reader.
@type_check_only
class _reader:
@property
def dialect(self) -> Dialect: ...
line_num: int
def __iter__(self) -> Self: ...
def __next__(self) -> list[str]: ...
# This class is not exposed. It calls itself _csv.writer.
@type_check_only
class _writer:
@property
def dialect(self) -> Dialect: ...
def writerow(self, row: Iterable[Any]) -> Any: ...
def writerows(self, rows: Iterable[Iterable[Any]]) -> None: ...
def writer(
csvfile: SupportsWrite[str],

View File

@@ -1,9 +1,10 @@
import _typeshed
import sys
from _typeshed import ReadableBuffer, WriteableBuffer
from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer
from abc import abstractmethod
from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
from ctypes import CDLL, ArgumentError as ArgumentError, c_void_p
from typing import Any, ClassVar, Generic, TypeVar, overload
from typing import Any, ClassVar, Generic, TypeVar, final, overload, type_check_only
from typing_extensions import Self, TypeAlias
if sys.version_info >= (3, 9):
@@ -47,46 +48,79 @@ if sys.platform == "win32":
def LoadLibrary(name: str, load_flags: int = 0, /) -> int: ...
def FreeLibrary(handle: int, /) -> None: ...
class _CDataMeta(type):
# By default mypy complains about the following two methods, because strictly speaking cls
# might not be a Type[_CT]. However this can never actually happen, because the only class that
# uses _CDataMeta as its metaclass is _CData. So it's safe to ignore the errors here.
def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
else:
def dlclose(handle: int, /) -> None: ...
# The default for flag is RTLD_GLOBAL|RTLD_LOCAL, which is platform dependent.
def dlopen(name: StrOrBytesPath, flag: int = ..., /) -> int: ...
def dlsym(handle: int, name: str, /) -> int: ...
class _CData(metaclass=_CDataMeta):
if sys.version_info >= (3, 13):
# This class is not exposed. It calls itself _ctypes.CType_Type.
@type_check_only
class _CType_Type(type):
# By default mypy complains about the following two methods, because strictly speaking cls
# might not be a Type[_CT]. However this doesn't happen because this is only a
# metaclass for subclasses of _CData.
def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
_CTypeBaseType = _CType_Type
else:
_CTypeBaseType = type
# This class is not exposed.
@type_check_only
class _CData:
_b_base_: int
_b_needsfree_: bool
_objects: Mapping[Any, int] | None
# At runtime the following classmethods are available only on classes, not
# on instances. This can't be reflected properly in the type system:
#
# Structure.from_buffer(...) # valid at runtime
# Structure(...).from_buffer(...) # invalid at runtime
#
@classmethod
def from_buffer(cls, source: WriteableBuffer, offset: int = ...) -> Self: ...
@classmethod
def from_buffer_copy(cls, source: ReadableBuffer, offset: int = ...) -> Self: ...
@classmethod
def from_address(cls, address: int) -> Self: ...
@classmethod
def from_param(cls, value: Any, /) -> Self | _CArgObject: ...
@classmethod
def in_dll(cls, library: CDLL, name: str) -> Self: ...
def __buffer__(self, flags: int, /) -> memoryview: ...
def __release_buffer__(self, buffer: memoryview, /) -> None: ...
def __ctypes_from_outparam__(self, /) -> Self: ...
class _SimpleCData(_CData, Generic[_T]):
# this is a union of all the subclasses of _CData, which is useful because of
# the methods that are present on each of those subclasses which are not present
# on _CData itself.
_CDataType: TypeAlias = _SimpleCData[Any] | _Pointer[Any] | CFuncPtr | Union | Structure | Array[Any]
# This class is not exposed. It calls itself _ctypes.PyCSimpleType.
@type_check_only
class _PyCSimpleType(_CTypeBaseType):
def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ...
def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ...
def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ...
if sys.version_info < (3, 13):
# Inherited from CType_Type starting on 3.13
def __mul__(self: type[_CT], value: int, /) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __rmul__(self: type[_CT], value: int, /) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
class _SimpleCData(_CData, Generic[_T], metaclass=_PyCSimpleType):
value: _T
# The TypeVar can be unsolved here,
# but we can't use overloads without creating many, many mypy false-positive errors
def __init__(self, value: _T = ...) -> None: ... # pyright: ignore[reportInvalidTypeVarUse]
def __ctypes_from_outparam__(self, /) -> _T: ... # type: ignore[override]
class _CanCastTo(_CData): ...
class _PointerLike(_CanCastTo): ...
class _Pointer(_PointerLike, _CData, Generic[_CT]):
# This type is not exposed. It calls itself _ctypes.PyCPointerType.
@type_check_only
class _PyCPointerType(_CTypeBaseType):
def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ...
def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ...
def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ...
def set_type(self, type: Any, /) -> None: ...
if sys.version_info < (3, 13):
# Inherited from CType_Type starting on 3.13
def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
class _Pointer(_PointerLike, _CData, Generic[_CT], metaclass=_PyCPointerType):
_type_: type[_CT]
contents: _CT
@overload
@@ -105,16 +139,32 @@ def POINTER(type: None, /) -> type[c_void_p]: ...
def POINTER(type: type[_CT], /) -> type[_Pointer[_CT]]: ...
def pointer(obj: _CT, /) -> _Pointer[_CT]: ...
# This class is not exposed. It calls itself _ctypes.CArgObject.
@final
@type_check_only
class _CArgObject: ...
def byref(obj: _CData, offset: int = ...) -> _CArgObject: ...
def byref(obj: _CData | _CDataType, offset: int = ...) -> _CArgObject: ...
_ECT: TypeAlias = Callable[[_CData | None, CFuncPtr, tuple[_CData, ...]], _CData]
_ECT: TypeAlias = Callable[[_CData | _CDataType | None, CFuncPtr, tuple[_CData | _CDataType, ...]], _CDataType]
_PF: TypeAlias = tuple[int] | tuple[int, str | None] | tuple[int, str | None, Any]
class CFuncPtr(_PointerLike, _CData):
restype: type[_CData] | Callable[[int], Any] | None
argtypes: Sequence[type[_CData]]
# This class is not exposed. It calls itself _ctypes.PyCFuncPtrType.
@type_check_only
class _PyCFuncPtrType(_CTypeBaseType):
def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ...
def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ...
def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ...
if sys.version_info < (3, 13):
# Inherited from CType_Type starting on 3.13
def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
class CFuncPtr(_PointerLike, _CData, metaclass=_PyCFuncPtrType):
restype: type[_CDataType] | Callable[[int], Any] | None
argtypes: Sequence[type[_CDataType]]
errcheck: _ECT
# Abstract attribute that must be defined on subclasses
_flags_: ClassVar[int]
@@ -129,7 +179,7 @@ class CFuncPtr(_PointerLike, _CData):
if sys.platform == "win32":
@overload
def __init__(
self, vtbl_index: int, name: str, paramflags: tuple[_PF, ...] | None = ..., iid: _CData | None = ..., /
self, vtbl_index: int, name: str, paramflags: tuple[_PF, ...] | None = ..., iid: _CData | _CDataType | None = ..., /
) -> None: ...
def __call__(self, *args: Any, **kwargs: Any) -> Any: ...
@@ -137,30 +187,95 @@ class CFuncPtr(_PointerLike, _CData):
_GetT = TypeVar("_GetT")
_SetT = TypeVar("_SetT")
# This class is not exposed. It calls itself _ctypes.CField.
@final
@type_check_only
class _CField(Generic[_CT, _GetT, _SetT]):
offset: int
size: int
@overload
def __get__(self, instance: None, owner: type[Any] | None, /) -> Self: ...
@overload
def __get__(self, instance: Any, owner: type[Any] | None, /) -> _GetT: ...
if sys.version_info >= (3, 10):
@overload
def __get__(self, instance: None, owner: type[Any] | None = None, /) -> Self: ...
@overload
def __get__(self, instance: Any, owner: type[Any] | None = None, /) -> _GetT: ...
else:
@overload
def __get__(self, instance: None, owner: type[Any] | None, /) -> Self: ...
@overload
def __get__(self, instance: Any, owner: type[Any] | None, /) -> _GetT: ...
def __set__(self, instance: Any, value: _SetT, /) -> None: ...
class _StructUnionMeta(_CDataMeta):
_fields_: Sequence[tuple[str, type[_CData]] | tuple[str, type[_CData], int]]
_pack_: int
_anonymous_: Sequence[str]
# This class is not exposed. It calls itself _ctypes.UnionType.
@type_check_only
class _UnionType(_CTypeBaseType):
def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ...
def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ...
def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ...
# At runtime, various attributes are created on a Union subclass based
# on its _fields_. This method doesn't exist, but represents those
# dynamically created attributes.
def __getattr__(self, name: str) -> _CField[Any, Any, Any]: ...
if sys.version_info < (3, 13):
# Inherited from CType_Type starting on 3.13
def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
class Union(_CData, metaclass=_UnionType):
_fields_: ClassVar[Sequence[tuple[str, type[_CDataType]] | tuple[str, type[_CDataType], int]]]
_pack_: ClassVar[int]
_anonymous_: ClassVar[Sequence[str]]
if sys.version_info >= (3, 13):
_align_: ClassVar[int]
class _StructUnionBase(_CData, metaclass=_StructUnionMeta):
def __init__(self, *args: Any, **kw: Any) -> None: ...
def __getattr__(self, name: str) -> Any: ...
def __setattr__(self, name: str, value: Any) -> None: ...
class Union(_StructUnionBase): ...
class Structure(_StructUnionBase): ...
# This class is not exposed. It calls itself _ctypes.PyCStructType.
@type_check_only
class _PyCStructType(_CTypeBaseType):
def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ...
def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ...
def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ...
# At runtime, various attributes are created on a Structure subclass based
# on its _fields_. This method doesn't exist, but represents those
# dynamically created attributes.
def __getattr__(self, name: str) -> _CField[Any, Any, Any]: ...
if sys.version_info < (3, 13):
# Inherited from CType_Type starting on 3.13
def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
class Array(_CData, Generic[_CT]):
class Structure(_CData, metaclass=_PyCStructType):
_fields_: ClassVar[Sequence[tuple[str, type[_CDataType]] | tuple[str, type[_CDataType], int]]]
_pack_: ClassVar[int]
_anonymous_: ClassVar[Sequence[str]]
if sys.version_info >= (3, 13):
_align_: ClassVar[int]
def __init__(self, *args: Any, **kw: Any) -> None: ...
def __getattr__(self, name: str) -> Any: ...
def __setattr__(self, name: str, value: Any) -> None: ...
# This class is not exposed. It calls itself _ctypes.PyCArrayType.
@type_check_only
class _PyCArrayType(_CTypeBaseType):
def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ...
def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ...
def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ...
def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ...
if sys.version_info < (3, 13):
# Inherited from CType_Type starting on 3.13
def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
class Array(_CData, Generic[_CT], metaclass=_PyCArrayType):
@property
@abstractmethod
def _length_(self) -> int: ...
@@ -205,9 +320,15 @@ class Array(_CData, Generic[_CT]):
if sys.version_info >= (3, 9):
def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
def addressof(obj: _CData, /) -> int: ...
def alignment(obj_or_type: _CData | type[_CData], /) -> int: ...
def addressof(obj: _CData | _CDataType, /) -> int: ...
def alignment(obj_or_type: _CData | _CDataType | type[_CData | _CDataType], /) -> int: ...
def get_errno() -> int: ...
def resize(obj: _CData, size: int, /) -> None: ...
def resize(obj: _CData | _CDataType, size: int, /) -> None: ...
def set_errno(value: int, /) -> int: ...
def sizeof(obj_or_type: _CData | type[_CData], /) -> int: ...
def sizeof(obj_or_type: _CData | _CDataType | type[_CData | _CDataType], /) -> int: ...
def PyObj_FromPtr(address: int, /) -> Any: ...
def Py_DECREF(o: _T, /) -> _T: ...
def Py_INCREF(o: _T, /) -> _T: ...
def buffer_info(o: _CData | _CDataType | type[_CData | _CDataType], /) -> tuple[str, int, tuple[int, ...]]: ...
def call_cdeclfunction(address: int, arguments: tuple[Any, ...], /) -> Any: ...
def call_function(address: int, arguments: tuple[Any, ...], /) -> Any: ...

View File

@@ -1,6 +1,7 @@
import sys
from _typeshed import ReadOnlyBuffer, SupportsRead
from typing import IO, Any, NamedTuple, final, overload
from curses import _ncurses_version
from typing import IO, Any, final, overload
from typing_extensions import TypeAlias
# NOTE: This module is ordinarily only available on Unix, but the windows-curses
@@ -549,9 +550,4 @@ class window: # undocumented
@overload
def vline(self, y: int, x: int, ch: _ChType, n: int) -> None: ...
class _ncurses_version(NamedTuple):
major: int
minor: int
patch: int
ncurses_version: _ncurses_version

View File

@@ -0,0 +1,27 @@
from _curses import window
from typing import final
__version__: str
version: str
class error(Exception): ...
@final
class panel:
def above(self) -> panel: ...
def below(self) -> panel: ...
def bottom(self) -> None: ...
def hidden(self) -> bool: ...
def hide(self) -> None: ...
def move(self, y: int, x: int, /) -> None: ...
def replace(self, win: window, /) -> None: ...
def set_userptr(self, obj: object, /) -> None: ...
def show(self) -> None: ...
def top(self) -> None: ...
def userptr(self) -> object: ...
def window(self) -> window: ...
def bottom_panel() -> panel: ...
def new_panel(win: window, /) -> panel: ...
def top_panel() -> panel: ...
def update_panels() -> panel: ...

View File

@@ -1,7 +1,7 @@
import sys
from _typeshed import ReadOnlyBuffer, StrOrBytesPath
from types import TracebackType
from typing import TypeVar, overload
from typing import TypeVar, final, overload, type_check_only
from typing_extensions import Self, TypeAlias
if sys.platform != "win32":
@@ -13,6 +13,8 @@ if sys.platform != "win32":
library: str
# Actual typename dbm, not exposed by the implementation
@final
@type_check_only
class _dbm:
def close(self) -> None: ...
if sys.version_info >= (3, 13):
@@ -22,18 +24,17 @@ if sys.platform != "win32":
def __setitem__(self, key: _KeyType, value: _ValueType) -> None: ...
def __delitem__(self, key: _KeyType) -> None: ...
def __len__(self) -> int: ...
def __del__(self) -> None: ...
def __enter__(self) -> Self: ...
def __exit__(
self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None
) -> None: ...
@overload
def get(self, k: _KeyType) -> bytes | None: ...
def get(self, k: _KeyType, /) -> bytes | None: ...
@overload
def get(self, k: _KeyType, default: _T) -> bytes | _T: ...
def get(self, k: _KeyType, default: _T, /) -> bytes | _T: ...
def keys(self) -> list[bytes]: ...
def setdefault(self, k: _KeyType, default: _ValueType = ...) -> bytes: ...
# Don't exist at runtime
def setdefault(self, k: _KeyType, default: _ValueType = ..., /) -> bytes: ...
# This isn't true, but the class can't be instantiated. See #13024
__new__: None # type: ignore[assignment]
__init__: None # type: ignore[assignment]

View File

@@ -17,20 +17,13 @@ from decimal import (
Rounded as Rounded,
Subnormal as Subnormal,
Underflow as Underflow,
_ContextManager,
)
from types import TracebackType
from typing import Final
from typing_extensions import TypeAlias
_TrapType: TypeAlias = type[DecimalException]
class _ContextManager:
new_context: Context
saved_context: Context
def __init__(self, new_context: Context) -> None: ...
def __enter__(self) -> Context: ...
def __exit__(self, t: type[BaseException] | None, v: BaseException | None, tb: TracebackType | None) -> None: ...
__version__: Final[str]
__libmpdec_version__: Final[str]

View File

@@ -0,0 +1,80 @@
import sys
from _typeshed import ReadableBuffer
from collections.abc import Callable
from types import ModuleType
from typing import AnyStr, final, overload
from typing_extensions import Self, TypeAlias
_DigestMod: TypeAlias = str | Callable[[], HASH] | ModuleType | None
openssl_md_meth_names: frozenset[str]
class HASH:
@property
def digest_size(self) -> int: ...
@property
def block_size(self) -> int: ...
@property
def name(self) -> str: ...
def copy(self) -> Self: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def update(self, obj: ReadableBuffer, /) -> None: ...
if sys.version_info >= (3, 10):
class UnsupportedDigestmodError(ValueError): ...
if sys.version_info >= (3, 9):
class HASHXOF(HASH):
def digest(self, length: int) -> bytes: ... # type: ignore[override]
def hexdigest(self, length: int) -> str: ... # type: ignore[override]
@final
class HMAC:
@property
def digest_size(self) -> int: ...
@property
def block_size(self) -> int: ...
@property
def name(self) -> str: ...
def copy(self) -> Self: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def update(self, msg: ReadableBuffer) -> None: ...
@overload
def compare_digest(a: ReadableBuffer, b: ReadableBuffer, /) -> bool: ...
@overload
def compare_digest(a: AnyStr, b: AnyStr, /) -> bool: ...
def get_fips_mode() -> int: ...
def hmac_new(key: bytes | bytearray, msg: ReadableBuffer = b"", digestmod: _DigestMod = None) -> HMAC: ...
def new(name: str, string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_md5(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_sha1(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_sha224(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_sha256(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_sha384(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_sha512(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_sha3_224(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_sha3_256(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_sha3_384(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_sha3_512(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ...
def openssl_shake_128(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASHXOF: ...
def openssl_shake_256(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASHXOF: ...
else:
def new(name: str, string: ReadableBuffer = b"") -> HASH: ...
def openssl_md5(string: ReadableBuffer = b"") -> HASH: ...
def openssl_sha1(string: ReadableBuffer = b"") -> HASH: ...
def openssl_sha224(string: ReadableBuffer = b"") -> HASH: ...
def openssl_sha256(string: ReadableBuffer = b"") -> HASH: ...
def openssl_sha384(string: ReadableBuffer = b"") -> HASH: ...
def openssl_sha512(string: ReadableBuffer = b"") -> HASH: ...
def hmac_digest(key: bytes | bytearray, msg: ReadableBuffer, digest: str) -> bytes: ...
def pbkdf2_hmac(
hash_name: str, password: ReadableBuffer, salt: ReadableBuffer, iterations: int, dklen: int | None = None
) -> bytes: ...
def scrypt(
password: ReadableBuffer, *, salt: ReadableBuffer, n: int, r: int, p: int, maxmem: int = 0, dklen: int = 64
) -> bytes: ...

View File

@@ -45,5 +45,6 @@ class make_scanner:
def __init__(self, context: make_scanner) -> None: ...
def __call__(self, string: str, index: int) -> tuple[Any, int]: ...
def encode_basestring(s: str, /) -> str: ...
def encode_basestring_ascii(s: str, /) -> str: ...
def scanstring(string: str, end: int, strict: bool = ...) -> tuple[str, int]: ...

View File

@@ -0,0 +1,44 @@
from _typeshed import ReadableBuffer
from codecs import _ReadableStream, _WritableStream
from collections.abc import Iterable
from typing import final, type_check_only
# This class is not exposed. It calls itself _multibytecodec.MultibyteCodec.
@final
@type_check_only
class _MultibyteCodec:
def decode(self, input: ReadableBuffer, errors: str | None = None) -> str: ...
def encode(self, input: str, errors: str | None = None) -> bytes: ...
class MultibyteIncrementalDecoder:
errors: str
def __init__(self, errors: str = "strict") -> None: ...
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
def getstate(self) -> tuple[bytes, int]: ...
def reset(self) -> None: ...
def setstate(self, state: tuple[bytes, int], /) -> None: ...
class MultibyteIncrementalEncoder:
errors: str
def __init__(self, errors: str = "strict") -> None: ...
def encode(self, input: str, final: bool = False) -> bytes: ...
def getstate(self) -> int: ...
def reset(self) -> None: ...
def setstate(self, state: int, /) -> None: ...
class MultibyteStreamReader:
errors: str
stream: _ReadableStream
def __init__(self, stream: _ReadableStream, errors: str = "strict") -> None: ...
def read(self, sizeobj: int | None = None, /) -> str: ...
def readline(self, sizeobj: int | None = None, /) -> str: ...
def readlines(self, sizehintobj: int | None = None, /) -> list[str]: ...
def reset(self) -> None: ...
class MultibyteStreamWriter:
errors: str
stream: _WritableStream
def __init__(self, stream: _WritableStream, errors: str = "strict") -> None: ...
def reset(self) -> None: ...
def write(self, strobj: str, /) -> None: ...
def writelines(self, lines: Iterable[str], /) -> None: ...

View File

@@ -4,7 +4,6 @@ from collections.abc import Callable, Sequence
from typing import SupportsIndex
if sys.platform != "win32":
def cloexec_pipe() -> tuple[int, int]: ...
def fork_exec(
args: Sequence[StrOrBytesPath] | None,
executable_list: Sequence[bytes],

View File

@@ -3,7 +3,7 @@ from _typeshed import ReadableBuffer, WriteableBuffer
from collections.abc import Iterable
from socket import error as error, gaierror as gaierror, herror as herror, timeout as timeout
from typing import Any, SupportsIndex, overload
from typing_extensions import TypeAlias
from typing_extensions import CapsuleType, TypeAlias
_CMSG: TypeAlias = tuple[int, int, bytes]
_CMSGArg: TypeAlias = tuple[int, int, ReadableBuffer]
@@ -72,7 +72,8 @@ SO_SNDBUF: int
SO_SNDLOWAT: int
SO_SNDTIMEO: int
SO_TYPE: int
SO_USELOOPBACK: int
if sys.platform != "linux":
SO_USELOOPBACK: int
if sys.platform == "win32":
SO_EXCLUSIVEADDRUSE: int
if sys.platform != "win32":
@@ -87,7 +88,10 @@ if sys.platform != "win32" and sys.platform != "darwin":
SO_PEERSEC: int
SO_PRIORITY: int
SO_PROTOCOL: int
if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux":
SO_SETFIB: int
if sys.platform == "linux" and sys.version_info >= (3, 13):
SO_BINDTOIFINDEX: int
SOMAXCONN: int
@@ -99,27 +103,32 @@ MSG_TRUNC: int
MSG_WAITALL: int
if sys.platform != "win32":
MSG_DONTWAIT: int
MSG_EOF: int
MSG_EOR: int
MSG_NOSIGNAL: int # Sometimes this exists on darwin, sometimes not
if sys.platform != "darwin":
MSG_BCAST: int
MSG_ERRQUEUE: int
if sys.platform == "win32":
MSG_BCAST: int
MSG_MCAST: int
if sys.platform != "win32" and sys.platform != "darwin":
MSG_BTAG: int
MSG_CMSG_CLOEXEC: int
MSG_CONFIRM: int
MSG_ETAG: int
MSG_FASTOPEN: int
MSG_MORE: int
if sys.platform != "win32" and sys.platform != "linux":
MSG_EOF: int
if sys.platform != "win32" and sys.platform != "linux" and sys.platform != "darwin":
MSG_NOTIFICATION: int
MSG_BTAG: int # Not FreeBSD either
MSG_ETAG: int # Not FreeBSD either
SOL_IP: int
SOL_SOCKET: int
SOL_TCP: int
SOL_UDP: int
if sys.platform != "win32" and sys.platform != "darwin":
# Defined in socket.h for Linux, but these aren't always present for
# some reason.
SOL_ATALK: int
SOL_AX25: int
SOL_HCI: int
@@ -128,10 +137,11 @@ if sys.platform != "win32" and sys.platform != "darwin":
SOL_ROSE: int
if sys.platform != "win32":
SCM_CREDS: int
SCM_RIGHTS: int
if sys.platform != "win32" and sys.platform != "darwin":
SCM_CREDENTIALS: int
if sys.platform != "win32" and sys.platform != "linux":
SCM_CREDS: int
IPPROTO_ICMP: int
IPPROTO_IP: int
@@ -143,21 +153,22 @@ IPPROTO_DSTOPTS: int
IPPROTO_EGP: int
IPPROTO_ESP: int
IPPROTO_FRAGMENT: int
IPPROTO_GGP: int
IPPROTO_HOPOPTS: int
IPPROTO_ICMPV6: int
IPPROTO_IDP: int
IPPROTO_IGMP: int
IPPROTO_IPV4: int
IPPROTO_IPV6: int
IPPROTO_MAX: int
IPPROTO_ND: int
IPPROTO_NONE: int
IPPROTO_PIM: int
IPPROTO_PUP: int
IPPROTO_ROUTING: int
IPPROTO_SCTP: int
if sys.platform != "darwin":
if sys.platform != "linux":
IPPROTO_GGP: int
IPPROTO_IPV4: int
IPPROTO_MAX: int
IPPROTO_ND: int
if sys.platform == "win32":
IPPROTO_CBT: int
IPPROTO_ICLFXBM: int
IPPROTO_IGP: int
@@ -166,18 +177,19 @@ if sys.platform != "darwin":
IPPROTO_RDP: int
IPPROTO_ST: int
if sys.platform != "win32":
IPPROTO_EON: int
IPPROTO_GRE: int
IPPROTO_HELLO: int
IPPROTO_IPCOMP: int
IPPROTO_IPIP: int
IPPROTO_RSVP: int
IPPROTO_TP: int
if sys.platform != "win32" and sys.platform != "linux":
IPPROTO_EON: int
IPPROTO_HELLO: int
IPPROTO_IPCOMP: int
IPPROTO_XTP: int
if sys.platform != "win32" and sys.platform != "darwin":
IPPROTO_BIP: int
IPPROTO_MOBILE: int
IPPROTO_VRRP: int
if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux":
IPPROTO_BIP: int # Not FreeBSD either
IPPROTO_MOBILE: int # Not FreeBSD either
IPPROTO_VRRP: int # Not FreeBSD either
if sys.version_info >= (3, 9) and sys.platform == "linux":
# Availability: Linux >= 2.6.20, FreeBSD >= 10.1
IPPROTO_UDPLITE: int
@@ -202,11 +214,10 @@ IP_MULTICAST_IF: int
IP_MULTICAST_LOOP: int
IP_MULTICAST_TTL: int
IP_OPTIONS: int
IP_RECVDSTADDR: int
if sys.platform != "linux":
IP_RECVDSTADDR: int
if sys.version_info >= (3, 10):
IP_RECVTOS: int
elif sys.platform != "win32" and sys.platform != "darwin":
IP_RECVTOS: int
IP_TOS: int
IP_TTL: int
if sys.platform != "win32":
@@ -218,6 +229,7 @@ if sys.platform != "win32":
IP_RETOPTS: int
if sys.platform != "win32" and sys.platform != "darwin":
IP_TRANSPARENT: int
if sys.platform != "win32" and sys.platform != "darwin" and sys.version_info >= (3, 11):
IP_BIND_ADDRESS_NO_PORT: int
if sys.version_info >= (3, 12):
IP_ADD_SOURCE_MEMBERSHIP: int
@@ -255,6 +267,9 @@ if sys.platform != "win32":
IPV6_RECVPATHMTU: int
IPV6_RECVPKTINFO: int
IPV6_RTHDRDSTOPTS: int
if sys.platform != "win32" and sys.platform != "linux":
if sys.version_info >= (3, 9) or sys.platform != "darwin":
IPV6_USE_MIN_MTU: int
EAI_AGAIN: int
@@ -268,11 +283,12 @@ EAI_SERVICE: int
EAI_SOCKTYPE: int
if sys.platform != "win32":
EAI_ADDRFAMILY: int
EAI_OVERFLOW: int
EAI_SYSTEM: int
if sys.platform != "win32" and sys.platform != "linux":
EAI_BADHINTS: int
EAI_MAX: int
EAI_OVERFLOW: int
EAI_PROTOCOL: int
EAI_SYSTEM: int
AI_ADDRCONFIG: int
AI_ALL: int
@@ -281,7 +297,7 @@ AI_NUMERICHOST: int
AI_NUMERICSERV: int
AI_PASSIVE: int
AI_V4MAPPED: int
if sys.platform != "win32":
if sys.platform != "win32" and sys.platform != "linux":
AI_DEFAULT: int
AI_MASK: int
AI_V4MAPPED_CFG: int
@@ -293,6 +309,8 @@ NI_NAMEREQD: int
NI_NOFQDN: int
NI_NUMERICHOST: int
NI_NUMERICSERV: int
if sys.platform == "linux" and sys.version_info >= (3, 13):
NI_IDN: int
TCP_FASTOPEN: int
TCP_KEEPCNT: int
@@ -318,6 +336,27 @@ if sys.platform != "win32" and sys.platform != "darwin":
TCP_SYNCNT: int
TCP_USER_TIMEOUT: int
TCP_WINDOW_CLAMP: int
if sys.platform == "linux" and sys.version_info >= (3, 12):
TCP_CC_INFO: int
TCP_FASTOPEN_CONNECT: int
TCP_FASTOPEN_KEY: int
TCP_FASTOPEN_NO_COOKIE: int
TCP_INQ: int
TCP_MD5SIG: int
TCP_MD5SIG_EXT: int
TCP_QUEUE_SEQ: int
TCP_REPAIR: int
TCP_REPAIR_OPTIONS: int
TCP_REPAIR_QUEUE: int
TCP_REPAIR_WINDOW: int
TCP_SAVED_SYN: int
TCP_SAVE_SYN: int
TCP_THIN_DUPACK: int
TCP_THIN_LINEAR_TIMEOUTS: int
TCP_TIMESTAMP: int
TCP_TX_DELAY: int
TCP_ULP: int
TCP_ZEROCOPY_RECEIVE: int
# --------------------
# Specifically documented constants
@@ -334,12 +373,13 @@ if sys.platform == "linux":
CAN_ERR_FLAG: int
CAN_ERR_MASK: int
CAN_RAW: int
CAN_RAW_ERR_FILTER: int
CAN_RAW_FILTER: int
CAN_RAW_LOOPBACK: int
CAN_RAW_RECV_OWN_MSGS: int
CAN_RTR_FLAG: int
CAN_SFF_MASK: int
if sys.version_info < (3, 11):
CAN_RAW_ERR_FILTER: int
if sys.platform == "linux":
# Availability: Linux >= 2.6.25
@@ -437,12 +477,13 @@ if sys.platform == "linux":
AF_RDS: int
PF_RDS: int
SOL_RDS: int
# These are present in include/linux/rds.h but don't always show up
# here.
RDS_CANCEL_SENT_TO: int
RDS_CMSG_RDMA_ARGS: int
RDS_CMSG_RDMA_DEST: int
RDS_CMSG_RDMA_MAP: int
RDS_CMSG_RDMA_STATUS: int
RDS_CMSG_RDMA_UPDATE: int
RDS_CONG_MONITOR: int
RDS_FREE_MR: int
RDS_GET_MR: int
@@ -456,6 +497,10 @@ if sys.platform == "linux":
RDS_RDMA_USE_ONCE: int
RDS_RECVERR: int
# This is supported by CPython but doesn't seem to be a real thing.
# The closest existing constant in rds.h is RDS_CMSG_CONG_UPDATE
# RDS_CMSG_RDMA_UPDATE: int
if sys.platform == "win32":
SIO_RCVALL: int
SIO_KEEPALIVE_VALS: int
@@ -522,16 +567,17 @@ if sys.platform == "linux":
if sys.platform != "win32" or sys.version_info >= (3, 9):
# Documented as only available on BSD, macOS, but empirically sometimes
# available on Windows
AF_LINK: int
if sys.platform != "linux":
AF_LINK: int
has_ipv6: bool
if sys.platform != "darwin":
if sys.platform != "darwin" and sys.platform != "linux":
if sys.platform != "win32" or sys.version_info >= (3, 9):
BDADDR_ANY: str
BDADDR_LOCAL: str
if sys.platform != "win32" and sys.platform != "darwin":
if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux":
HCI_FILTER: int # not in NetBSD or DragonFlyBSD
HCI_TIME_STAMP: int # not in FreeBSD, NetBSD, or DragonFlyBSD
HCI_DATA_DIR: int # not in FreeBSD, NetBSD, or DragonFlyBSD
@@ -580,36 +626,37 @@ if sys.version_info >= (3, 12):
if sys.platform == "linux":
# Netlink is defined by Linux
AF_NETLINK: int
NETLINK_ARPD: int
NETLINK_CRYPTO: int
NETLINK_DNRTMSG: int
NETLINK_FIREWALL: int
NETLINK_IP6_FW: int
NETLINK_NFLOG: int
NETLINK_ROUTE6: int
NETLINK_ROUTE: int
NETLINK_SKIP: int
NETLINK_TAPBASE: int
NETLINK_TCPDIAG: int
NETLINK_USERSOCK: int
NETLINK_W1: int
NETLINK_XFRM: int
# Technically still supported by CPython
# NETLINK_ARPD: int # linux 2.0 to 2.6.12 (EOL August 2005)
# NETLINK_ROUTE6: int # linux 2.2 to 2.6.12 (EOL August 2005)
# NETLINK_SKIP: int # linux 2.0 to 2.6.12 (EOL August 2005)
# NETLINK_TAPBASE: int # linux 2.2 to 2.6.12 (EOL August 2005)
# NETLINK_TCPDIAG: int # linux 2.6.0 to 2.6.13 (EOL December 2005)
# NETLINK_W1: int # linux 2.6.13 to 2.6.17 (EOL October 2006)
if sys.platform == "darwin":
PF_SYSTEM: int
SYSPROTO_CONTROL: int
if sys.platform != "darwin":
if sys.platform != "darwin" and sys.platform != "linux":
if sys.version_info >= (3, 9) or sys.platform != "win32":
AF_BLUETOOTH: int
if sys.platform != "win32" and sys.platform != "darwin":
if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux":
# Linux and some BSD support is explicit in the docs
# Windows and macOS do not support in practice
BTPROTO_HCI: int
BTPROTO_L2CAP: int
BTPROTO_SCO: int # not in FreeBSD
if sys.platform != "darwin":
if sys.platform != "darwin" and sys.platform != "linux":
if sys.version_info >= (3, 9) or sys.platform != "win32":
BTPROTO_RFCOMM: int
@@ -636,13 +683,14 @@ AF_SNA: int
if sys.platform != "win32":
AF_ROUTE: int
if sys.platform == "darwin":
AF_SYSTEM: int
if sys.platform != "darwin":
AF_IRDA: int
if sys.platform != "win32" and sys.platform != "darwin":
AF_AAL5: int
AF_ASH: int
AF_ATMPVC: int
AF_ATMSVC: int
@@ -661,10 +709,12 @@ if sys.platform != "win32" and sys.platform != "darwin":
# Miscellaneous undocumented
if sys.platform != "win32":
if sys.platform != "win32" and sys.platform != "linux":
LOCAL_PEERCRED: int
if sys.platform != "win32" and sys.platform != "darwin":
# Defined in linux socket.h, but this isn't always present for
# some reason.
IPX_TYPE: int
# ===== Classes =====
@@ -792,4 +842,4 @@ def if_nameindex() -> list[tuple[int, str]]: ...
def if_nametoindex(oname: str, /) -> int: ...
def if_indextoname(index: int, /) -> str: ...
CAPI: object
CAPI: CapsuleType

View File

@@ -44,6 +44,12 @@ def start_new_thread(function: Callable[[Unpack[_Ts]], object], args: tuple[Unpa
@overload
def start_new_thread(function: Callable[..., object], args: tuple[Any, ...], kwargs: dict[str, Any], /) -> int: ...
# Obsolete synonym for start_new_thread()
@overload
def start_new(function: Callable[[Unpack[_Ts]], object], args: tuple[Unpack[_Ts]], /) -> int: ...
@overload
def start_new(function: Callable[..., object], args: tuple[Any, ...], kwargs: dict[str, Any], /) -> int: ...
if sys.version_info >= (3, 10):
def interrupt_main(signum: signal.Signals = ..., /) -> None: ...
@@ -51,7 +57,9 @@ else:
def interrupt_main() -> None: ...
def exit() -> NoReturn: ...
def exit_thread() -> NoReturn: ... # Obsolete synonym for exit()
def allocate_lock() -> LockType: ...
def allocate() -> LockType: ... # Obsolete synonym for allocate_lock()
def get_ident() -> int: ...
def stack_size(size: int = 0, /) -> int: ...

View File

@@ -1,3 +1,4 @@
from threading import RLock
from typing import Any
from typing_extensions import Self, TypeAlias
from weakref import ReferenceType
@@ -8,6 +9,9 @@ _LocalDict: TypeAlias = dict[Any, Any]
class _localimpl:
key: str
dicts: dict[int, tuple[ReferenceType[Any], _LocalDict]]
# Keep localargs in sync with the *args, **kwargs annotation on local.__new__
localargs: tuple[list[Any], dict[str, Any]]
locallock: RLock
def get_dict(self) -> _LocalDict: ...
def create_dict(self) -> _LocalDict: ...

View File

@@ -107,7 +107,7 @@ class object:
@property
def __class__(self) -> type[Self]: ...
@__class__.setter
def __class__(self, type: type[object], /) -> None: ...
def __class__(self, type: type[Self], /) -> None: ...
def __init__(self) -> None: ...
def __new__(cls) -> Self: ...
# N.B. `object.__setattr__` and `object.__delattr__` are heavily special-cased by type checkers.
@@ -1963,14 +1963,33 @@ class StopAsyncIteration(Exception):
class SyntaxError(Exception):
msg: str
filename: str | None
lineno: int | None
offset: int | None
text: str | None
filename: str | None
# Errors are displayed differently if this attribute exists on the exception.
# The value is always None.
print_file_and_line: None
if sys.version_info >= (3, 10):
end_lineno: int | None
end_offset: int | None
@overload
def __init__(self) -> None: ...
@overload
def __init__(self, msg: object, /) -> None: ...
# Second argument is the tuple (filename, lineno, offset, text)
@overload
def __init__(self, msg: str, info: tuple[str | None, int | None, int | None, str | None], /) -> None: ...
if sys.version_info >= (3, 10):
# end_lineno and end_offset must both be provided if one is.
@overload
def __init__(
self, msg: str, info: tuple[str | None, int | None, int | None, str | None, int | None, int | None], /
) -> None: ...
# If you provide more than two arguments, it still creates the SyntaxError, but
# the arguments from the info tuple are not parsed. This form is omitted.
class SystemError(Exception): ...
class TypeError(Exception): ...
class ValueError(Exception): ...

View File

@@ -126,6 +126,7 @@ class BZ2File(BaseStream, IO[bytes]):
def readline(self, size: SupportsIndex = -1) -> bytes: ... # type: ignore[override]
def readinto(self, b: WriteableBuffer) -> int: ...
def readlines(self, size: SupportsIndex = -1) -> list[bytes]: ...
def peek(self, n: int = 0) -> bytes: ...
def seek(self, offset: int, whence: int = 0) -> int: ...
def write(self, data: ReadableBuffer) -> int: ...
def writelines(self, seq: Iterable[ReadableBuffer]) -> None: ...

View File

@@ -3,7 +3,7 @@ from _codecs import *
from _typeshed import ReadableBuffer
from abc import abstractmethod
from collections.abc import Callable, Generator, Iterable
from typing import Any, BinaryIO, Final, Literal, Protocol, TextIO
from typing import Any, BinaryIO, ClassVar, Final, Literal, Protocol, TextIO
from typing_extensions import Self
__all__ = [
@@ -202,6 +202,7 @@ class StreamWriter(Codec):
def write(self, object: str) -> None: ...
def writelines(self, list: Iterable[str]) -> None: ...
def reset(self) -> None: ...
def seek(self, offset: int, whence: int = 0) -> None: ...
def __enter__(self) -> Self: ...
def __exit__(self, type: type[BaseException] | None, value: BaseException | None, tb: types.TracebackType | None) -> None: ...
def __getattr__(self, name: str, getattr: Callable[[Any, str], Any] = ...) -> Any: ...
@@ -209,11 +210,14 @@ class StreamWriter(Codec):
class StreamReader(Codec):
stream: _ReadableStream
errors: str
# This is set to str, but some subclasses set to bytes instead.
charbuffertype: ClassVar[type] = ...
def __init__(self, stream: _ReadableStream, errors: str = "strict") -> None: ...
def read(self, size: int = -1, chars: int = -1, firstline: bool = False) -> str: ...
def readline(self, size: int | None = None, keepends: bool = True) -> str: ...
def readlines(self, sizehint: int | None = None, keepends: bool = True) -> list[str]: ...
def reset(self) -> None: ...
def seek(self, offset: int, whence: int = 0) -> None: ...
def __enter__(self) -> Self: ...
def __exit__(self, type: type[BaseException] | None, value: BaseException | None, tb: types.TracebackType | None) -> None: ...
def __iter__(self) -> Self: ...

View File

@@ -1,5 +1,5 @@
import sys
from _typeshed import StrOrBytesPath, SupportsWrite
from _typeshed import MaybeNone, StrOrBytesPath, SupportsWrite
from collections.abc import Callable, ItemsView, Iterable, Iterator, Mapping, MutableMapping, Sequence
from re import Pattern
from typing import Any, ClassVar, Final, Literal, TypeVar, overload
@@ -263,11 +263,11 @@ class RawConfigParser(_Parser):
) -> _T: ...
# This is incompatible with MutableMapping so we ignore the type
@overload # type: ignore[override]
def get(self, section: str, option: str, *, raw: bool = False, vars: _Section | None = None) -> str | Any: ...
def get(self, section: str, option: str, *, raw: bool = False, vars: _Section | None = None) -> str | MaybeNone: ...
@overload
def get(
self, section: str, option: str, *, raw: bool = False, vars: _Section | None = None, fallback: _T
) -> str | _T | Any: ...
) -> str | _T | MaybeNone: ...
@overload
def items(self, *, raw: bool = False, vars: _Section | None = None) -> ItemsView[str, SectionProxy]: ...
@overload
@@ -277,6 +277,8 @@ class RawConfigParser(_Parser):
def remove_option(self, section: str, option: str) -> bool: ...
def remove_section(self, section: str) -> bool: ...
def optionxform(self, optionstr: str) -> str: ...
@property
def converters(self) -> ConverterMapping: ...
class ConfigParser(RawConfigParser):
# This is incompatible with MutableMapping so we ignore the type
@@ -300,28 +302,34 @@ class SectionProxy(MutableMapping[str, str]):
def parser(self) -> RawConfigParser: ...
@property
def name(self) -> str: ...
def get( # type: ignore[override]
# This is incompatible with MutableMapping so we ignore the type
@overload # type: ignore[override]
def get(
self, option: str, *, raw: bool = False, vars: _Section | None = None, _impl: Any | None = None, **kwargs: Any
) -> str | None: ...
@overload
def get(
self,
option: str,
fallback: str | None = None,
fallback: _T,
*,
raw: bool = False,
vars: _Section | None = None,
_impl: Any | None = None,
**kwargs: Any,
) -> str | Any: ... # can be None in RawConfigParser's sections
) -> str | _T: ...
# These are partially-applied version of the methods with the same names in
# RawConfigParser; the stubs should be kept updated together
@overload
def getint(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> int: ...
def getint(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> int | None: ...
@overload
def getint(self, option: str, fallback: _T = ..., *, raw: bool = ..., vars: _Section | None = ...) -> int | _T: ...
@overload
def getfloat(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> float: ...
def getfloat(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> float | None: ...
@overload
def getfloat(self, option: str, fallback: _T = ..., *, raw: bool = ..., vars: _Section | None = ...) -> float | _T: ...
@overload
def getboolean(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> bool: ...
def getboolean(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> bool | None: ...
@overload
def getboolean(self, option: str, fallback: _T = ..., *, raw: bool = ..., vars: _Section | None = ...) -> bool | _T: ...
# SectionProxy can have arbitrary attributes when custom converters are used

View File

@@ -1,7 +1,7 @@
import abc
import sys
from _typeshed import FileDescriptorOrPath, Unused
from abc import abstractmethod
from abc import ABC, abstractmethod
from collections.abc import AsyncGenerator, AsyncIterator, Awaitable, Callable, Generator, Iterator
from types import TracebackType
from typing import IO, Any, Generic, Protocol, TypeVar, overload, runtime_checkable
@@ -38,16 +38,22 @@ _P = ParamSpec("_P")
_ExitFunc: TypeAlias = Callable[[type[BaseException] | None, BaseException | None, TracebackType | None], bool | None]
_CM_EF = TypeVar("_CM_EF", bound=AbstractContextManager[Any, Any] | _ExitFunc)
# mypy and pyright object to this being both ABC and Protocol.
# At runtime it inherits from ABC and is not a Protocol, but it is on the
# allowlist for use as a Protocol.
@runtime_checkable
class AbstractContextManager(Protocol[_T_co, _ExitT_co]):
class AbstractContextManager(ABC, Protocol[_T_co, _ExitT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __enter__(self) -> _T_co: ...
@abstractmethod
def __exit__(
self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None, /
) -> _ExitT_co: ...
# mypy and pyright object to this being both ABC and Protocol.
# At runtime it inherits from ABC and is not a Protocol, but it is on the
# allowlist for use as a Protocol.
@runtime_checkable
class AbstractAsyncContextManager(Protocol[_T_co, _ExitT_co]):
class AbstractAsyncContextManager(ABC, Protocol[_T_co, _ExitT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
async def __aenter__(self) -> _T_co: ...
@abstractmethod
async def __aexit__(

View File

@@ -1,8 +1,15 @@
import sys
from typing import Final
from typing import Final, NamedTuple, type_check_only
if sys.platform != "win32":
class _Method: ...
@type_check_only
class _MethodBase(NamedTuple):
name: str
ident: str | None
salt_chars: int
total_size: int
class _Method(_MethodBase): ...
METHOD_CRYPT: Final[_Method]
METHOD_MD5: Final[_Method]
METHOD_SHA256: Final[_Method]

View File

@@ -8,8 +8,6 @@ from _csv import (
__version__ as __version__,
_DialectLike,
_QuotingType,
_reader,
_writer,
field_size_limit as field_size_limit,
get_dialect as get_dialect,
list_dialects as list_dialects,
@@ -21,6 +19,10 @@ from _csv import (
if sys.version_info >= (3, 12):
from _csv import QUOTE_NOTNULL as QUOTE_NOTNULL, QUOTE_STRINGS as QUOTE_STRINGS
if sys.version_info >= (3, 10):
from _csv import Reader, Writer
else:
from _csv import _reader as Reader, _writer as Writer
from _typeshed import SupportsWrite
from collections.abc import Collection, Iterable, Mapping, Sequence
@@ -77,7 +79,7 @@ class DictReader(Generic[_T]):
fieldnames: Sequence[_T] | None
restkey: _T | None
restval: str | Any | None
reader: _reader
reader: Reader
dialect: _DialectLike
line_num: int
@overload
@@ -125,7 +127,7 @@ class DictWriter(Generic[_T]):
fieldnames: Collection[_T]
restval: Any | None
extrasaction: Literal["raise", "ignore"]
writer: _writer
writer: Writer
def __init__(
self,
f: SupportsWrite[str],

View File

@@ -10,13 +10,11 @@ from _ctypes import (
_CanCastTo as _CanCastTo,
_CArgObject as _CArgObject,
_CData as _CData,
_CDataMeta as _CDataMeta,
_CDataType as _CDataType,
_CField as _CField,
_Pointer as _Pointer,
_PointerLike as _PointerLike,
_SimpleCData as _SimpleCData,
_StructUnionBase as _StructUnionBase,
_StructUnionMeta as _StructUnionMeta,
addressof as addressof,
alignment as alignment,
byref as byref,
@@ -28,7 +26,7 @@ from _ctypes import (
)
from ctypes._endian import BigEndianStructure as BigEndianStructure, LittleEndianStructure as LittleEndianStructure
from typing import Any, ClassVar, Generic, TypeVar
from typing_extensions import TypeAlias
from typing_extensions import Self, TypeAlias, deprecated
if sys.platform == "win32":
from _ctypes import FormatError as FormatError, get_last_error as get_last_error, set_last_error as set_last_error
@@ -41,6 +39,7 @@ if sys.version_info >= (3, 9):
_T = TypeVar("_T")
_DLLT = TypeVar("_DLLT", bound=CDLL)
_CT = TypeVar("_CT", bound=_CData)
DEFAULT_MODE: int
@@ -48,7 +47,7 @@ class ArgumentError(Exception): ...
class CDLL:
_func_flags_: ClassVar[int]
_func_restype_: ClassVar[_CData]
_func_restype_: ClassVar[_CDataType]
_name: str
_handle: int
_FuncPtr: type[_FuncPointer]
@@ -91,15 +90,21 @@ class _NamedFuncPointer(_FuncPointer):
__name__: str
def CFUNCTYPE(
restype: type[_CData] | None, *argtypes: type[_CData], use_errno: bool = ..., use_last_error: bool = ...
restype: type[_CData | _CDataType] | None,
*argtypes: type[_CData | _CDataType],
use_errno: bool = ...,
use_last_error: bool = ...,
) -> type[_FuncPointer]: ...
if sys.platform == "win32":
def WINFUNCTYPE(
restype: type[_CData] | None, *argtypes: type[_CData], use_errno: bool = ..., use_last_error: bool = ...
restype: type[_CData | _CDataType] | None,
*argtypes: type[_CData | _CDataType],
use_errno: bool = ...,
use_last_error: bool = ...,
) -> type[_FuncPointer]: ...
def PYFUNCTYPE(restype: type[_CData] | None, *argtypes: type[_CData]) -> type[_FuncPointer]: ...
def PYFUNCTYPE(restype: type[_CData | _CDataType] | None, *argtypes: type[_CData | _CDataType]) -> type[_FuncPointer]: ...
# Any type that can be implicitly converted to c_void_p when passed as a C function argument.
# (bytes is not included here, see below.)
@@ -112,12 +117,17 @@ _CVoidConstPLike: TypeAlias = _CVoidPLike | bytes
_CastT = TypeVar("_CastT", bound=_CanCastTo)
def cast(obj: _CData | _CArgObject | int, typ: type[_CastT]) -> _CastT: ...
def cast(obj: _CData | _CDataType | _CArgObject | int, typ: type[_CastT]) -> _CastT: ...
def create_string_buffer(init: int | bytes, size: int | None = None) -> Array[c_char]: ...
c_buffer = create_string_buffer
def create_unicode_buffer(init: int | str, size: int | None = None) -> Array[c_wchar]: ...
@deprecated("Deprecated in Python 3.13; removal scheduled for Python 3.15")
def SetPointerType(
pointer: type[_Pointer[Any]], cls: Any # noqa: F811 # Redefinition of unused `pointer` from line 22
) -> None: ...
def ARRAY(typ: _CT, len: int) -> Array[_CT]: ... # Soft Deprecated, no plans to remove
if sys.platform == "win32":
def DllCanUnloadNow() -> int: ...
@@ -126,12 +136,12 @@ if sys.platform == "win32":
def memmove(dst: _CVoidPLike, src: _CVoidConstPLike, count: int) -> int: ...
def memset(dst: _CVoidPLike, c: int, count: int) -> int: ...
def string_at(address: _CVoidConstPLike, size: int = -1) -> bytes: ...
def string_at(ptr: _CVoidConstPLike, size: int = -1) -> bytes: ...
if sys.platform == "win32":
def WinError(code: int | None = None, descr: str | None = None) -> OSError: ...
def wstring_at(address: _CVoidConstPLike, size: int = -1) -> str: ...
def wstring_at(ptr: _CVoidConstPLike, size: int = -1) -> str: ...
class c_byte(_SimpleCData[int]): ...
@@ -140,6 +150,8 @@ class c_char(_SimpleCData[bytes]):
class c_char_p(_PointerLike, _SimpleCData[bytes | None]):
def __init__(self, value: int | bytes | None = ...) -> None: ...
@classmethod
def from_param(cls, value: Any, /) -> Self | _CArgObject: ...
class c_double(_SimpleCData[float]): ...
class c_longdouble(_SimpleCData[float]): ... # can be an alias for c_double
@@ -155,7 +167,13 @@ class c_uint(_SimpleCData[int]): ... # can be an alias for c_ulong
class c_ulong(_SimpleCData[int]): ...
class c_ulonglong(_SimpleCData[int]): ... # can be an alias for c_ulong
class c_ushort(_SimpleCData[int]): ...
class c_void_p(_PointerLike, _SimpleCData[int | None]): ...
class c_void_p(_PointerLike, _SimpleCData[int | None]):
@classmethod
def from_param(cls, value: Any, /) -> Self | _CArgObject: ...
c_voidp = c_void_p # backwards compatibility (to a bug)
class c_wchar(_SimpleCData[str]): ...
c_int8 = c_byte
@@ -174,6 +192,8 @@ class c_uint64(_SimpleCData[int]): ...
class c_wchar_p(_PointerLike, _SimpleCData[str | None]):
def __init__(self, value: int | str | None = ...) -> None: ...
@classmethod
def from_param(cls, value: Any, /) -> Self | _CArgObject: ...
class c_bool(_SimpleCData[bool]):
def __init__(self, value: bool = ...) -> None: ...

View File

@@ -0,0 +1 @@
__version__: str

View File

@@ -0,0 +1,8 @@
from collections.abc import Mapping
from ctypes.macholib.dylib import dylib_info as dylib_info
from ctypes.macholib.framework import framework_info as framework_info
__all__ = ["dyld_find", "framework_find", "framework_info", "dylib_info"]
def dyld_find(name: str, executable_path: str | None = None, env: Mapping[str, str] | None = None) -> str: ...
def framework_find(fn: str, executable_path: str | None = None, env: Mapping[str, str] | None = None) -> str: ...

View File

@@ -0,0 +1,14 @@
from typing import TypedDict, type_check_only
__all__ = ["dylib_info"]
# Actual result is produced by re.match.groupdict()
@type_check_only
class _DylibInfo(TypedDict):
location: str
name: str
shortname: str
version: str | None
suffix: str | None
def dylib_info(filename: str) -> _DylibInfo | None: ...

View File

@@ -0,0 +1,14 @@
from typing import TypedDict, type_check_only
__all__ = ["framework_info"]
# Actual result is produced by re.match.groupdict()
@type_check_only
class _FrameworkInfo(TypedDict):
location: str
name: str
shortname: str
version: str | None
suffix: str | None
def framework_info(filename: str) -> _FrameworkInfo | None: ...

View File

@@ -4,3 +4,5 @@ def find_library(name: str) -> str | None: ...
if sys.platform == "win32":
def find_msvcrt() -> str | None: ...
def test() -> None: ...

View File

@@ -1,7 +1,7 @@
from _ctypes import _CArgObject, _CField
from ctypes import (
Array,
Structure,
_CField,
_Pointer,
_SimpleCData,
c_byte,
@@ -21,8 +21,8 @@ from ctypes import (
c_wchar,
c_wchar_p,
)
from typing import TypeVar
from typing_extensions import TypeAlias
from typing import Any, TypeVar
from typing_extensions import Self, TypeAlias
BYTE = c_byte
WORD = c_ushort
@@ -241,10 +241,16 @@ LPBYTE = PBYTE
PBOOLEAN = PBYTE
# LP_c_char
class PCHAR(_Pointer[CHAR]): ...
class PCHAR(_Pointer[CHAR]):
# this is inherited from ctypes.c_char_p, kind of.
@classmethod
def from_param(cls, value: Any, /) -> Self | _CArgObject: ...
# LP_c_wchar
class PWCHAR(_Pointer[WCHAR]): ...
class PWCHAR(_Pointer[WCHAR]):
# inherited from ctypes.c_wchar_p, kind of
@classmethod
def from_param(cls, value: Any, /) -> Self | _CArgObject: ...
# LP_c_void_p
class PHANDLE(_Pointer[HANDLE]): ...

View File

@@ -1,7 +1,9 @@
import sys
from _curses import *
from _curses import window as window
from _typeshed import structseq
from collections.abc import Callable
from typing import TypeVar
from typing import Final, TypeVar, final, type_check_only
from typing_extensions import Concatenate, ParamSpec
# NOTE: The _curses module is ordinarily only available on Unix, but the
@@ -25,3 +27,19 @@ def wrapper(func: Callable[Concatenate[window, _P], _T], /, *arg: _P.args, **kwd
# it was mapped to the name 'window' in 3.8.
# Kept here as a legacy alias in case any third-party code is relying on it.
_CursesWindow = window
# At runtime this class is unexposed and calls itself curses.ncurses_version.
# That name would conflict with the actual curses.ncurses_version, which is
# an instance of this class.
@final
@type_check_only
class _ncurses_version(structseq[int], tuple[int, int, int]):
if sys.version_info >= (3, 10):
__match_args__: Final = ("major", "minor", "patch")
@property
def major(self) -> int: ...
@property
def minor(self) -> int: ...
@property
def patch(self) -> int: ...

View File

@@ -1,22 +1 @@
from _curses import window
version: str
class _Curses_Panel: # type is <class '_curses_panel.curses panel'> (note the space in the class name)
def above(self) -> _Curses_Panel: ...
def below(self) -> _Curses_Panel: ...
def bottom(self) -> None: ...
def hidden(self) -> bool: ...
def hide(self) -> None: ...
def move(self, y: int, x: int) -> None: ...
def replace(self, win: window) -> None: ...
def set_userptr(self, obj: object) -> None: ...
def show(self) -> None: ...
def top(self) -> None: ...
def userptr(self) -> object: ...
def window(self) -> window: ...
def bottom_panel() -> _Curses_Panel: ...
def new_panel(win: window, /) -> _Curses_Panel: ...
def top_panel() -> _Curses_Panel: ...
def update_panels() -> _Curses_Panel: ...
from _curses_panel import *

View File

@@ -1,8 +1,8 @@
import sys
from abc import abstractmethod
from time import struct_time
from typing import ClassVar, Final, NamedTuple, NoReturn, SupportsIndex, final, overload
from typing_extensions import Self, TypeAlias, deprecated
from typing import ClassVar, Final, NoReturn, SupportsIndex, final, overload, type_check_only
from typing_extensions import CapsuleType, Self, TypeAlias, deprecated
if sys.version_info >= (3, 11):
__all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo", "MINYEAR", "MAXYEAR", "UTC")
@@ -40,10 +40,17 @@ if sys.version_info >= (3, 11):
UTC: timezone
if sys.version_info >= (3, 9):
class _IsoCalendarDate(NamedTuple):
year: int
week: int
weekday: int
# This class calls itself datetime.IsoCalendarDate. It's neither
# NamedTuple nor structseq.
@final
@type_check_only
class _IsoCalendarDate(tuple[int, int, int]):
@property
def year(self) -> int: ...
@property
def week(self) -> int: ...
@property
def weekday(self) -> int: ...
class date:
min: ClassVar[date]
@@ -325,3 +332,5 @@ class datetime(date):
def __sub__(self, value: Self, /) -> timedelta: ...
@overload
def __sub__(self, value: timedelta, /) -> Self: ...
datetime_CAPI: CapsuleType

View File

@@ -2,7 +2,7 @@ import sys
from _typeshed import StrOrBytesPath
from collections.abc import Iterator, MutableMapping
from types import TracebackType
from typing import Literal
from typing import Literal, type_check_only
from typing_extensions import Self, TypeAlias
__all__ = ["open", "whichdb", "error"]
@@ -89,6 +89,8 @@ class _Database(MutableMapping[_KeyType, bytes]):
self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None
) -> None: ...
# This class is not exposed. It calls itself dbm.error.
@type_check_only
class _error(Exception): ...
error: tuple[type[_error], type[OSError]]

View File

@@ -24,7 +24,8 @@ from _decimal import (
setcontext as setcontext,
)
from collections.abc import Container, Sequence
from typing import Any, ClassVar, Literal, NamedTuple, overload
from types import TracebackType
from typing import Any, ClassVar, Literal, NamedTuple, final, overload, type_check_only
from typing_extensions import Self, TypeAlias
_Decimal: TypeAlias = Decimal | int
@@ -35,6 +36,14 @@ _TrapType: TypeAlias = type[DecimalException]
# At runtime, these classes are implemented in C as part of "_decimal".
# However, they consider themselves to live in "decimal", so we'll put them here.
# This type isn't exposed at runtime. It calls itself decimal.ContextManager
@final
@type_check_only
class _ContextManager:
def __init__(self, new_context: Context) -> None: ...
def __enter__(self) -> Context: ...
def __exit__(self, t: type[BaseException] | None, v: BaseException | None, tb: TracebackType | None) -> None: ...
class DecimalTuple(NamedTuple):
sign: int
digits: tuple[int, ...]

View File

@@ -165,7 +165,7 @@ class CCompiler:
def execute(
self, func: Callable[[Unpack[_Ts]], Unused], args: tuple[Unpack[_Ts]], msg: str | None = None, level: int = 1
) -> None: ...
def spawn(self, cmd: list[str]) -> None: ...
def spawn(self, cmd: Iterable[str]) -> None: ...
def mkpath(self, name: str, mode: int = 0o777) -> None: ...
@overload
def move_file(self, src: StrPath, dst: _StrPathT) -> _StrPathT | str: ...

View File

@@ -1,6 +1,10 @@
from collections.abc import Iterable
from typing import Literal
def spawn(
cmd: list[str], search_path: bool | Literal[0, 1] = 1, verbose: bool | Literal[0, 1] = 0, dry_run: bool | Literal[0, 1] = 0
cmd: Iterable[str],
search_path: bool | Literal[0, 1] = 1,
verbose: bool | Literal[0, 1] = 0,
dry_run: bool | Literal[0, 1] = 0,
) -> None: ...
def find_executable(executable: str, path: str | None = None) -> str | None: ...

View File

@@ -3,7 +3,7 @@ import types
import unittest
from _typeshed import ExcInfo
from collections.abc import Callable
from typing import Any, ClassVar, NamedTuple
from typing import Any, NamedTuple, type_check_only
from typing_extensions import Self, TypeAlias
__all__ = [
@@ -42,17 +42,15 @@ __all__ = [
"debug",
]
# MyPy errors on conditionals within named tuples.
if sys.version_info >= (3, 13):
class TestResults(NamedTuple):
def __new__(cls, failed: int, attempted: int, *, skipped: int = 0) -> Self: ... # type: ignore[misc]
skipped: int
@type_check_only
class _TestResultsBase(NamedTuple):
failed: int
attempted: int
_fields: ClassVar = ("failed", "attempted") # type: ignore[misc]
__match_args__ = ("failed", "attempted") # type: ignore[misc]
__doc__: None # type: ignore[misc]
class TestResults(_TestResultsBase):
def __new__(cls, failed: int, attempted: int, *, skipped: int = 0) -> Self: ...
skipped: int
else:
class TestResults(NamedTuple):

View File

@@ -4,6 +4,29 @@ from email.policy import Policy
from typing import IO
from typing_extensions import TypeAlias
# At runtime, listing submodules in __all__ without them being imported is
# valid, and causes them to be included in a star import. See #6523
__all__ = [ # noqa: F822 # Undefined names in __all__
"base64mime", # pyright: ignore[reportUnsupportedDunderAll]
"charset", # pyright: ignore[reportUnsupportedDunderAll]
"encoders", # pyright: ignore[reportUnsupportedDunderAll]
"errors", # pyright: ignore[reportUnsupportedDunderAll]
"feedparser", # pyright: ignore[reportUnsupportedDunderAll]
"generator", # pyright: ignore[reportUnsupportedDunderAll]
"header", # pyright: ignore[reportUnsupportedDunderAll]
"iterators", # pyright: ignore[reportUnsupportedDunderAll]
"message", # pyright: ignore[reportUnsupportedDunderAll]
"message_from_file",
"message_from_binary_file",
"message_from_string",
"message_from_bytes",
"mime", # pyright: ignore[reportUnsupportedDunderAll]
"parser", # pyright: ignore[reportUnsupportedDunderAll]
"quoprimime", # pyright: ignore[reportUnsupportedDunderAll]
"utils", # pyright: ignore[reportUnsupportedDunderAll]
]
# Definitions imported by multiple submodules in typeshed
_ParamType: TypeAlias = str | tuple[str | None, str | None, str] # noqa: Y047
_ParamsType: TypeAlias = str | None | tuple[str, str | None, str] # noqa: Y047
@@ -12,18 +35,3 @@ def message_from_string(s: str, _class: Callable[[], Message] = ..., *, policy:
def message_from_bytes(s: bytes | bytearray, _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ...
def message_from_file(fp: IO[str], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ...
def message_from_binary_file(fp: IO[bytes], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ...
# Names in __all__ with no definition:
# base64mime
# charset
# encoders
# errors
# feedparser
# generator
# header
# iterators
# message
# mime
# parser
# quoprimime
# utils

View File

@@ -5,6 +5,8 @@ from email.message import Message
from typing import Generic, Protocol, TypeVar, type_check_only
from typing_extensions import Self
__all__ = ["Policy", "Compat32", "compat32"]
_MessageT = TypeVar("_MessageT", bound=Message, default=Message)
@type_check_only

View File

@@ -0,0 +1 @@
aliases: dict[str, str]

View File

@@ -0,0 +1,30 @@
import codecs
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
# At runtime, this is codecs.ascii_encode
@staticmethod
def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ...
# At runtime, this is codecs.ascii_decode
@staticmethod
def decode(data: ReadableBuffer, errors: str | None = None, /) -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
# Note: encode being a decode function and decode being an encode function is accurate to runtime.
class StreamConverter(StreamWriter, StreamReader): # type: ignore[misc] # incompatible methods in base classes
# At runtime, this is codecs.ascii_decode
@staticmethod
def encode(data: ReadableBuffer, errors: str | None = None, /) -> tuple[str, int]: ... # type: ignore[override]
# At runtime, this is codecs.ascii_encode
@staticmethod
def decode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... # type: ignore[override]
def getregentry() -> codecs.CodecInfo: ...

View File

@@ -0,0 +1,26 @@
import codecs
from _typeshed import ReadableBuffer
from typing import ClassVar
# This codec is bytes to bytes.
def base64_encode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ...
def base64_decode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ...
class Codec(codecs.Codec):
def encode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override]
def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override]
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override]
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override]
class StreamWriter(Codec, codecs.StreamWriter):
charbuffertype: ClassVar[type] = ...
class StreamReader(Codec, codecs.StreamReader):
charbuffertype: ClassVar[type] = ...
def getregentry() -> codecs.CodecInfo: ...

View File

@@ -0,0 +1,23 @@
import _multibytecodec as mbc
import codecs
from typing import ClassVar
codec: mbc._MultibyteCodec
class Codec(codecs.Codec):
encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc]
codec: ClassVar[mbc._MultibyteCodec] = ...
class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder):
codec: ClassVar[mbc._MultibyteCodec] = ...
class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc]
codec: ClassVar[mbc._MultibyteCodec] = ...
class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter):
codec: ClassVar[mbc._MultibyteCodec] = ...
def getregentry() -> codecs.CodecInfo: ...

View File

@@ -0,0 +1,23 @@
import _multibytecodec as mbc
import codecs
from typing import ClassVar
codec: mbc._MultibyteCodec
class Codec(codecs.Codec):
encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc]
codec: ClassVar[mbc._MultibyteCodec] = ...
class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder):
codec: ClassVar[mbc._MultibyteCodec] = ...
class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc]
codec: ClassVar[mbc._MultibyteCodec] = ...
class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter):
codec: ClassVar[mbc._MultibyteCodec] = ...
def getregentry() -> codecs.CodecInfo: ...

View File

@@ -0,0 +1,26 @@
import codecs
from _typeshed import ReadableBuffer
from typing import ClassVar
# This codec is bytes to bytes.
def bz2_encode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ...
def bz2_decode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ...
class Codec(codecs.Codec):
def encode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override]
def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override]
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override]
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override]
class StreamWriter(Codec, codecs.StreamWriter):
charbuffertype: ClassVar[type] = ...
class StreamReader(Codec, codecs.StreamReader):
charbuffertype: ClassVar[type] = ...
def getregentry() -> codecs.CodecInfo: ...

View File

@@ -0,0 +1,33 @@
import codecs
from _codecs import _CharMap
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
# At runtime, this is codecs.charmap_encode
@staticmethod
def encode(str: str, errors: str | None = None, mapping: _CharMap | None = None, /) -> tuple[bytes, int]: ...
# At runtime, this is codecs.charmap_decode
@staticmethod
def decode(data: ReadableBuffer, errors: str | None = None, mapping: _CharMap | None = None, /) -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
mapping: _CharMap | None
def __init__(self, errors: str = "strict", mapping: _CharMap | None = None) -> None: ...
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
mapping: _CharMap | None
def __init__(self, errors: str = "strict", mapping: _CharMap | None = None) -> None: ...
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter):
mapping: _CharMap | None
def __init__(self, stream: codecs._WritableStream, errors: str = "strict", mapping: _CharMap | None = None) -> None: ...
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override]
class StreamReader(Codec, codecs.StreamReader):
mapping: _CharMap | None
def __init__(self, stream: codecs._ReadableStream, errors: str = "strict", mapping: _CharMap | None = None) -> None: ...
def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[str, int]: ... # type: ignore[override]
def getregentry() -> codecs.CodecInfo: ...

View File

@@ -0,0 +1,21 @@
import codecs
from _codecs import _EncodingMap
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ...
def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
def getregentry() -> codecs.CodecInfo: ...
decoding_table: str
encoding_table: _EncodingMap

View File

@@ -0,0 +1,21 @@
import codecs
from _codecs import _EncodingMap
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ...
def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
def getregentry() -> codecs.CodecInfo: ...
decoding_table: str
encoding_table: _EncodingMap

View File

@@ -0,0 +1,21 @@
import codecs
from _codecs import _EncodingMap
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ...
def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
def getregentry() -> codecs.CodecInfo: ...
decoding_table: str
encoding_table: _EncodingMap

View File

@@ -0,0 +1,21 @@
import codecs
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ...
def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
def getregentry() -> codecs.CodecInfo: ...
decoding_map: dict[int, int | None]
decoding_table: str
encoding_map: dict[int, int]

View File

@@ -0,0 +1,21 @@
import codecs
from _codecs import _EncodingMap
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ...
def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
def getregentry() -> codecs.CodecInfo: ...
decoding_table: str
encoding_table: _EncodingMap

View File

@@ -0,0 +1,21 @@
import codecs
from _codecs import _EncodingMap
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ...
def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
def getregentry() -> codecs.CodecInfo: ...
decoding_table: str
encoding_table: _EncodingMap

View File

@@ -0,0 +1,21 @@
import codecs
from _codecs import _EncodingMap
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ...
def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
def getregentry() -> codecs.CodecInfo: ...
decoding_table: str
encoding_table: _EncodingMap

View File

@@ -0,0 +1,21 @@
import codecs
from _codecs import _EncodingMap
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ...
def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
def getregentry() -> codecs.CodecInfo: ...
decoding_table: str
encoding_table: _EncodingMap

View File

@@ -0,0 +1,21 @@
import codecs
from _codecs import _EncodingMap
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ...
def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
def getregentry() -> codecs.CodecInfo: ...
decoding_table: str
encoding_table: _EncodingMap

View File

@@ -0,0 +1,21 @@
import codecs
from _codecs import _EncodingMap
from _typeshed import ReadableBuffer
class Codec(codecs.Codec):
def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ...
def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ...
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input: str, final: bool = False) -> bytes: ...
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input: ReadableBuffer, final: bool = False) -> str: ...
class StreamWriter(Codec, codecs.StreamWriter): ...
class StreamReader(Codec, codecs.StreamReader): ...
def getregentry() -> codecs.CodecInfo: ...
decoding_table: str
encoding_table: _EncodingMap

Some files were not shown because too many files have changed in this diff Show More