Repository navigation
Merge upstream - #216
Merge upstream#216
Conversation
Concrete subclasses of generic dataclass-transform classes retained the base class's type variables in inherited converter inputs, rejecting valid constructor calls, attribute assignments, and `__replace__` calls. Specialize the types stored in field metadata so these operations accept the subclass's concrete type arguments. Apply type mappings to field defaults and converter input/output types, and avoid applying the specialization twice when collecting Pydantic right-hand-side defaults. Fixes astral-sh/ty#4677. ## Test plan Manually compared constructor signatures for equivalent right-hand-side and `Annotated` Pydantic field defaults using minimal local stubs before and after the change. Both forms retained matching defaults under generic specialization.
Comparisons on narrowed operands can return objects other than `bool`, but intersection comparison inference intersected those results with `bool`. This could turn a valid comparison into `Never` and hide errors in code that remains reachable. Resolve rich-comparison methods with the full intersection receiver so non-boolean results and `Self` constraints are preserved. Keep boolean simplifications for boolean results, respect reflected-method priority, and use inherited `object` comparison methods only as fallbacks. Preserve union alternatives within each intersection component's return type, with a conservative union fallback when distributing them would exceed the complexity limit. Retain definite equality and inequality results for gradual operands narrowed to `None`. Fixes astral-sh/ty#4380. ## Ecosystem report Analyzed head: `9ea38ae03484b349136e8fb102c21fcb1938ef72`. Most changes are expected off-by-default unsoundness warnings for gradual comparison results. Preserving non-boolean results also removes false unreachable-branch diagnostics and exposes existing downstream annotation mismatches; reflected arithmetic becomes more precise. No remaining ecosystem regressions were identified. [Full ecosystem analysis](astral-sh/ruff#28045 (comment)). The current-head memory report and [CodSpeed comparison](https://app.codspeed.io/astral-sh/ruff/runs/compare/6abc0e147d32f5eb9f94ffd2..6abc1f087d32f5eb9f95019d) show no material performance regression.
## Summary
We now avoid a stack overflow when checking recursive protocol methods
with intersection types:
```python
from __future__ import annotations
from typing import Protocol, reveal_type
from ty_extensions import Intersection, Not
class A[T](Protocol):
def make_invariant(self, value: T) -> T: ...
def cause_problems(self) -> A[Intersection[Not[A[T]], A[str]]]: ...
def foo[T](x: A[T]):
reveal_type(x.cause_problems().cause_problems())
```
Specifically, we now specialize protocol members only when they are
accessed or compared, avoiding eager expansion of recursive return
types.
Closes astral-sh/ty#4099.
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [icu_normalizer](https://icu4x.unicode.org) ([source](https://redirect.github.com/unicode-org/icu4x)) | workspace.dependencies | minor | `2.2.0` → `2.3.0` | --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "before 4am on Wednesday" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/astral-sh/ruff). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMzQuMSIsInVwZGF0ZWRJblZlciI6IjQ0LjEzNC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJpbnRlcm5hbCJdfQ==--> --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
Constraint set relations now take a `ConstraintProvenance` parameter, allowing the provenance of the constraint set to be chosen upon construction, instead of a forcing a second pass to create a set of validity constraints. See astral-sh/ruff#28909 (comment).
Add eight- and sixteen-case benchmarks for tuple class patterns that capture attributes. Successive cases create correlated tuple alternatives and wide element unions, reproducing the expensive checking reported in astral-sh/ty#4676. The smaller workload also measures the cost of shorter match statements. ## Test plan Parent: `5ce273da22e1`. Head: `7e0103df61e7`. Measured on macOS-26.7.1-arm64-arm-64bit with optimized debug builds (opt-level 1, LTO off). Criterion values are medians of three run means; CLI values are medians of 15 warmed runs, with variants interleaved. Reductions use geometric means of matched head/parent ratios (which differ from ratios of the displayed medians); small Criterion differences remain uncertain with only three rounds. One 32-case CLI comparison round interrupted by system sleep was repeated in full. | Workload | Benchmark baseline median | | --- | --- | | 8 cases, Criterion | 0.250 s | | 16 cases, Criterion | 2.554 s | | 8 cases, CLI | 0.226 s | | 32 cases, CLI | 14.836 s | The 32-case CLI input uses the original issue’s tuple/class-pattern workload scaled to 32 cases; it is a separate fixture from the 16-case Criterion workload.
When checking whether an intersection is disjoint from a type it explicitly excludes, test that exclusion before visiting unrelated positive components. This avoids unnecessary relation checks while normalizing the intersections produced by tuple pattern narrowing. Gradual types retain the full reflexive subtyping check. Related to astral-sh/ty#4676. ## Test plan Parent: `7e0103df61e7`. Head: `339c848e2e43`. Measured on Apple Silicon with macOS 26.7.1 using optimized debug builds (opt-level 1, LTO off). Criterion values are medians of three run means; CLI values are medians of 15 warmed runs, with variants interleaved. Reductions use geometric means of matched head/parent ratios (which differ from ratios of the displayed medians); small Criterion differences remain uncertain with only three rounds. | Workload | Parent median | Head median | Paired time reduction | | --- | --- | --- | --- | | 8 cases, Criterion | 0.232 s | 0.190 s | +18.4% | | 16 cases, Criterion | 2.343 s | 1.853 s | +20.0% | | 8 cases, CLI | 0.223 s | 0.189 s | +15.4% | | 32 cases, CLI | 14.664 s | 12.261 s | +15.9% | The 32-case CLI input uses the original issue’s tuple/class-pattern workload scaled to 32 cases; it is a separate fixture from the 16-case Criterion workload.
For `["x"] if flag else []`, ty currently infers `list[Unknown]`.
Similarly, `{"x": 1} if flag else {}` is inferred as `dict[Unknown,
Unknown]`.
Infer the nonempty branch first when the other branch is an empty
literal of the same kind. This lets the empty branch use its peer’s type
as context, so both branch orders infer `list[str]` and `dict[str, int]`
for these examples.
Adapted from @tamird's [original
change](tamird/ruff@7914a95).
---------
Co-authored-by: Tamir Duberstein <tamird@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
## Summary Reverts #29059, which caused a new stack overflow when inferring nested generic protocol specializations (astral-sh/ty#4694). This also removes the original fix for astral-sh/ty#4099, which will need a different approach. Closes astral-sh/ty#4694.
Follow-up to #29151: upgrade the benchmark dependency from hyperfine 2.0.0-alpha.2 to 2.0.0. Use `--env RAYON_NUM_THREADS=1` instead of an `env` command prefix for the single-threaded formatter benchmarks. This avoids measuring the overhead of `env` itself (~5 ms).
Ruff's release pipeline publishes unsigned macOS and Windows binaries. Add shared actions to sign Windows binaries and sign and notarize macOS binaries, then reassemble wheels and GitHub archives with updated `RECORD` entries and checksums before publication. Use 16 KiB code-signature pages for ARM64 macOS binaries to reduce signature-verification work. Signing uses the protected `release` environment and the repository's `main` workflow, including release dry runs.
Release signing fails while collecting `powerpc64-unknown-linux-gnu` wheels because the target remains in `dist-workspace.toml` after #22766 removed its builds. Remove the stale entry so the signing inventory matches the release build matrix. Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary We now check that attribute and property overrides preserve the types that can be read and written through the superclass. The checks extend `invalid-attribute-override` and introduce two separately configurable rules, following the distinction proposed in [ty#2158](astral-sh/ty#2158). ### `invalid-attribute-override` We reject ordinary attributes whose readable type is incompatible with the inherited declaration. This rule is enabled by default: ```python class Base: value: int class Child(Base): value: str # Now rejected: invalid-attribute-override. ``` The rule also rejects removing write access, such as replacing a writable attribute with a `Final` attribute, and retains the existing checks for incompatible `ClassVar` qualifiers. ### `invalid-property-type-override` We reject incompatible property result types, setters that accept fewer values than the inherited setter, and getter-only properties that replace writable attributes. This rule is also enabled by default: ```python class Base: @Property def value(self) -> int: return 0 class Child(Base): @Property def value(self) -> str: # Now rejected: invalid-property-type-override. return "" ``` A read-only property returning `bool` would be a valid override of this `int` property. Reads can become more specific; writes must continue to accept every value permitted by the superclass. ### `invalid-mutable-override` Narrowing a writable attribute's type preserves reads but restricts writes. We report this separately, and leave the rule disabled by default: ```python class Base: value: int class Child(Base): value: bool # invalid-mutable-override, when enabled. def reset(obj: Base) -> None: obj.value = 42 child = Child() reset(child) # Allowed through Base, but child.value is no longer a bool. ``` This distinction lets users opt into mutable invariance without changing the other override checks. ## Case analysis ### Cached properties in Home Assistant The [ecosystem report](https://fed09ff3.ty-ecosystem-ext.pages.dev/diff) adds 6,986 `invalid-property-type-override` diagnostics. Home Assistant accounts for 6,863 of those, including 6,861 cases where a read-only property replaces a writable attribute. A common pattern is [BlueCurrentEntity.available](https://github.com/home-assistant/core/blob/8f4c394961405acec82bc01f24620359736617b3/homeassistant/components/blue_current/entity.py#L43), which replaces the inherited [Entity.available cached property](https://github.com/home-assistant/core/blob/8f4c394961405acec82bc01f24620359736617b3/homeassistant/helpers/entity.py#L870) with a getter-only property: ```python from functools import cached_property class Entity: @cached_property def available(self) -> bool: return True class IntegrationEntity(Entity): @Property def available(self) -> bool: # Now rejected: invalid-property-type-override. return True def mark_unavailable(entity: Entity) -> None: entity.available = False mark_unavailable(Entity()) # Succeeds. mark_unavailable(IntegrationEntity()) # Raises AttributeError. ``` Both getters return `bool`, but the override removes a supported write (a `cached_property` stores its value in the instance dictionary and permits assignment to replace it, even before the first read, so it's writable). This PR retains the diagnostic (it's correct, after all): a function accepting `Entity` can assign to `entity.available`. Replacing the cached property with a getter-only property makes that valid operation fail on subclass instances. (pyright 1.1.411 in standard mode rejects this override, but mypy 2.3.1 and pyrefly 1.2.0 with default checks accept it.) Part of astral-sh/ty#2158.
Comparisons between nominal instances with a non-generic target only inspect MRO class identities. Skip the recursion guard for these comparisons, avoiding its bookkeeping. Tuple targets and specialized generic targets retain the guard because their element or type-argument comparisons can recurse. Related to astral-sh/ty#4676. ## Test plan Parent: `4830211afdd4`. Head: `10168bb1e5dc`. Measured on Apple Silicon with macOS 26.7.1 using optimized debug builds (opt-level 1, LTO off). Criterion values are medians of three run means; CLI values are medians of 15 warmed runs, with variants interleaved. Reductions use geometric means of matched head/parent ratios (which differ from ratios of the displayed medians); small Criterion differences remain uncertain with only three rounds. | Workload | Parent median | Head median | Paired time reduction | | --- | --- | --- | --- | | 8 cases, Criterion | 0.195 s | 0.175 s | +9.1% | | 16 cases, Criterion | 1.874 s | 1.687 s | +11.6% | | 8 cases, CLI | 0.193 s | 0.177 s | +6.6% | | 32 cases, CLI | 12.139 s | 10.666 s | +11.8% | The eight-case CLI comparison is inconclusive in this run; the sixteen-case Criterion benchmark and 32-case CLI example show clearer gains. The 32-case CLI input uses the original issue’s tuple/class-pattern workload scaled to 32 cases; it is a separate fixture from the 16-case Criterion workload. CodSpeed results on the PR look like a smaller improvement than measured locally, but still significant. The [automatic CodSpeed report](astral-sh/ruff#29202 (comment)) compares `10168bb` with `4830211`. It identifies a 4.05% efficiency improvement in the eight-case CPU simulation benchmark, with 179 metrics classified as untouched and 60 skipped.
The Intel macOS wheel smoke test runs on an ARM runner. Although `setup-python` selects `x64`, its universal interpreter defaults to ARM, so `pip` rejects the signed Intel wheel as unsupported. Run the Python commands through the Intel slice for `x86_64-apple-darwin`, matching the architecture selection in astral-sh/uv#21532. Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
We now mark both branches of a condition with type `Never` as
unreachable:
```python
from typing import Never
def f(value: Never):
if value:
result = 1 # Unreachable.
else:
result = 2 # Also unreachable.
```
Previously, we treated `Never` as having ambiguous truthiness, allowing
either assignment to affect inference. In the reported loop, the
variables depend on each other, so including these impossible
assignments made their inferred types depend on which file we checked
first.
We add `Truthiness::Uninhabited` to represent the absence of either
boolean outcome. `Type::bool` and `Type::try_bool` return this variant
for `Never`, replacing the opt-in `bool_if_inhabited` API and making
callers handle the distinction explicitly.
Closes astral-sh/ty#4577.
Codex was overfitting its optimizations for tuple match narrowing to non-generic classes, when generic classes display similar or worse performance. Update the benchmark to also include the generic-class case, so we don't fail to optimize that as well. Add 8- and 16-case variants of the tuple class-pattern capture benchmark, using writable `T | None` attributes and class instances specialized with `int`. The existing non-generic benchmark names and generated inputs are unchanged. Related to astral-sh/ty#4676.
ty can allow assignment to or deletion of a `Final` instance attribute
when the receiver is a union or has been narrowed through a protocol.
Another member of the composite type can make the attribute appear
writable.
In this contrived example, ty previously accepted the assignment because
`Mutable.value` is writable. With this change, ty reports
`invalid-assignment` because the receiver could be a `Fixed` instance:
```python
from typing import Final
class Fixed:
def __init__(self) -> None:
self.value: Final[int] = 1
class Mutable:
value: int = 1
def update(either: Fixed | Mutable) -> None:
# previously this was fine, but with this PR:
either.value = 2 # error: [invalid-assignment]
```
Check the members of unions and positive intersection components for
`Final` restrictions. Assignment checks also follow type aliases, so an
aliased union member retains the restriction.
A class can still assign to its own `Final` attribute through `self` in
`__init__`, even when `self` is narrowed through a protocol. If several
union members prohibit the same assignment, ty reports one error and
stops checking rather than producing duplicate errors.
Adapted from @tamird’s [original
change](tamird/ruff@cf8a56c).
---------
Co-authored-by: Tamir Duberstein <tamird@gmail.com>
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [unicode-normalization](https://redirect.github.com/unicode-rs/unicode-normalization) | workspace.dependencies | patch | `0.1.24` → `0.1.25` | --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "before 4am on Wednesday" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/astral-sh/ruff). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNTkuNCIsInVwZGF0ZWRJblZlciI6IjQzLjE0MS4zIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJpbnRlcm5hbCJdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Summary -- This is the CLI accompaniment to #27807. The main change here is showing display-only fix diffs in the CLI. However, display-only fixes don't have a corresponding flag like `--unsafe-fixes`, and I thought it would be weird to show them unconditionally when we don't do the same for unsafe fixes, so this PR also unconditionally renders unsafe fix diffs, even when that flag isn't passed. We already emit a note about the fix being unsafe, so I think it makes sense always to show you the fix, and make `--unsafe-fixes` enable actually applying the fix. We also don't want to apply display-only fixes, so enabling rendering of the fixes with `--display-only-fixes` or similar would also disagree with the semantics of the unsafe flag. I'm open to other ideas here, though. The sub-diagnostic for display-only fixes uses a higher severity than the note for unsafe fixes and renders in red, as shown below. The change here also affects ty, which now has both unsafe and display-only fixes. I again checked what clippy and rustc do in these cases, and they don't include any additional note or warning about the fix being unsafe: <details><summary>Rust diagnostics</summary> <p> Here's a [`clippy::needless_pass_by_value`](https://rust-lang.github.io/rust-clippy/rust-1.97.0/index.html#needless_pass_by_value) diagnostic, which is `MaybeIncorrect` ( similar to our `Unsafe`): ``` warning: this argument is passed by value, but not consumed in the function body --> src/main.rs:3:15 | 3 | fn size(data: Data) -> usize { | ^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.97.0/index.html#needless_pass_by_value = note: requested on the command line with `-W clippy::needless-pass-by-value` help: consider taking a reference instead | 3 | fn size(data: &Data) -> usize { | + ``` and here's a rustc [`LetLike`](https://github.com/rust-lang/rust/blob/8bab26f4f68e0e26f0bb7960be334d5b520ea452/compiler/rustc_trait_selection/src/errors.rs#L268-L288) diagnostic, which is `has-placeholders` (similar to our `DisplayOnly` but definitely produces invalid code in this case): ``` error[E0282]: type annotations needed for `Vec<_>` --> placeholder.rs:2:9 | 2 | let values = Vec::new(); | ^^^^^^ ---------- type must be known at this point | help: consider giving `values` an explicit type, where the type for type parameter `T` is specified | 2 | let values: Vec<T> = Vec::new(); | ++++++++ ``` </p> </details> Fixes astral-sh/ty#1679 Test Plan -- Updated existing snapshots, and some manual testing in the CLI: <img width="965" height="400" alt="image" src="https://github.com/user-attachments/assets/888ad79a-6853-48d4-8344-48da4af47d74" /> --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This PR updates quick-junit to [v0.8.0](https://github.com/nextest-rs/quick-junit/releases/tag/quick-junit-0.8.0). The original renovate description of the bump to v0.7.0 is below. Note that I also had to update `fuzz/Cargo.lock` to get the fuzz build to run: ```console cargo update --manifest-path fuzz/Cargo.toml thiserror@2.0.18 --precise 2.0.20 ``` <hr> This PR contains the following updates: | Package | Type | Update | Change | Pending | |---|---|---|---|---| | [quick-junit](https://redirect.github.com/nextest-rs/quick-junit) | workspace.dependencies | minor | `0.6.0` → `0.7.0` | `0.8.0` | --- <details> <summary>nextest-rs/quick-junit (quick-junit)</summary> [`v0.7.0`](https://redirect.github.com/nextest-rs/quick-junit/blob/HEAD/CHANGELOG.md#070---2026-07-20) [Compare Source](https://redirect.github.com/nextest-rs/quick-junit/compare/quick-junit-0.6.1...quick-junit-0.7.0) Skipped test counts are now reported via the `skipped` attribute rather than `disabled`. For `<testsuite>`, `skipped` matches the [llg schema](https://llg.cubic.org/docs/junit/) and the Jenkins [junit-10 schema](https://redirect.github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd), as well as pytest and Maven Surefire. - Each `<testsuite>` now emits `skipped="N"`, and the root `<testsuites>` element now emits an aggregated `skipped="N"` count. Previously the root didn't carry a skip count at all. - Root-level `skipped` is a quick-junit extension. It follows the modern JUnit convention (as documented, for example, by [testmoapp/junitxml](https://redirect.github.com/testmoapp/junitxml)) and is similar to quick-junit's existing extensions such as `uuid`. - `TestSuite`'s `disabled` field has been renamed to `skipped`. - `Report` gains new public `skipped` and `disabled` fields, and `Report::add_test_suite` now aggregates skip counts into `Report::skipped`. `disabled` is now modeled as a separate optional count on both `Report` and `TestSuite`, distinct from `skipped`. (`disabled` is intended to count tests that are disabled by design, such as googletest's `DISABLED_`-prefixed tests. Note, however, that quick-junit doesn't have a notion of disabled tests at the moment.) - `Report` is now `#[non_exhaustive]`, consistent with `TestSuite` and `TestCase`. Construct it via `Report::new` and then assign fields, so that future field additions are non-breaking. - Childless `<testsuite>` and `<testcase>` elements are now serialized as self-closing tags (for example, `<testcase name="my-test"/>` rather than `<testcase name="my-test"></testcase>`). The output is semantically identical XML, only more compact and idiomatic. The deserializer already accepted these self-closing forms, so serializing them means round-trip tests now cover those parse paths. </details> --- 📅 **Schedule**: (UTC) - Branch creation - "before 4am on Wednesday" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/astral-sh/ruff). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQ0Ljc5LjEiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbImludGVybmFsIl19--> --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
Remove the deprecated `ruff-lsp` compatibility CI job, its dependency group and Python constraint, and the associated `pygls` Renovate rule. Prune ten unused packages from the root lockfile while preserving all remaining package versions and Git revisions. Related: astral-sh/ruff#28545, astral-sh/ruff-vscode#1170
Summary -- This makes a few modifications to our default rule set for v0.17. As the snapshots show, these had already been incorporated into our preview defaults via rule recategorization. This just ports them back to the stable default rules. This closes #27197, which brought the problems with the DTZ rules to our attention. F406 being a syntax error was raised in [this comment]. [this comment]: astral-sh/ruff#27199 (comment) Test Plan -- Updated snapshots
Summary -- I wasn't really planning to do a full stabilization pass, but I quickly skimmed through `preview.rs` and remembered that the isort pragma change was kind a bug fix but technically breaking and thought we might want to stabilize it. This PR stabilizes the isort pragma comment width handling introduced in #27313, along with the related pragma handling for `E501` and `W505` from #24071. There was a comment about also stabilizing the related formatter preview feature on the function from #24071, so that is stabilized here too. I'm fine holding off on this, especially if the formatter change is a better fit for the 2027 style guide. Like I said above, I mostly wanted to stabilize the isort change, but that snowballed a bit since the helpers were shared. Test Plan -- Updated existing snapshots
Update the editor documentation for the VS Code extension's transition to always using Ruff's native language server. Remove the retired `ruff-lsp` settings entries, links to those entries, and obsolete setup notes while retaining migration examples and replacement guidance. Document `ruff.nativeServer` as deprecated in Ruff 0.17 and describe `ruff.interpreter` solely in terms of executable discovery. Related: astral-sh/ruff#28545, astral-sh/ruff-vscode#1170 <!-- codex-thread: 01a0c3c7-f498-7682-9193-6e0e5307066b -->
## Summary We make redundancy comparisons converge when they participate in a Salsa inference cycle. Comparing inferred callable signatures can depend on the union being simplified: removing an alternative changes the inferred signatures, which can make the next comparison return a different answer. The query still starts with `true`, but combines successive results with `previous && current`. Once a comparison returns `false`, it remains false for that cycle. Retaining the union alternative prevents the comparison from oscillating; the tradeoff is that a redundant alternative may remain in the union. This is a prerequisite for #29553, whose stable lambda identities expose this cycle. The regression examples belong to that PR because they already terminate on `main`.
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
Linux CI installs `mold` by replacing the system linker, but the current Rust toolchain and MSRV already select bundled `lld` for `x86_64-unknown-linux-gnu`. Remove the installation steps to avoid downloading `mold` and changing the system linker for these jobs. [Eight pairs of `ruff` debug builds](https://github.com/astral-sh/ruff/actions/runs/39841713358) on 16-vCPU CI runners averaged 28.6 s with `mold` installation and 27.5 s without. Each pair built both variants on the same runner from empty target directories, with build order alternated. Times include installation when applicable and exclude dependency downloads. The mean change was −1.1 s (two-sided 90% paired t confidence interval: −8.8 to +6.7 s); the interval includes zero. The second build was faster in every pair, indicating a substantial order effect. Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
## Summary
This PR adds basic tests for Django support in ty, and adds a first
customization point where we now synthesize `.id` and `.pk` attributes
for primary keys on Django models. Django support currently relies on
`django-types`, a fork of `django-stubs` which requires less
special-casing in type checkers.
Example
```py
from django.db import models
class Book(models.Model):
isbn = models.CharField(max_length=13, primary_key=True)
title = models.CharField()
pages = models.IntegerField(null=True)
def _(book: Book):
reveal_type(book.isbn) # str
reveal_type(book.title) # str
reveal_type(book.pages) # int | None (because null=True)
reveal_type(book.pk) # str (because `isbn` is the primary key)
book.id # error: no automatic `id` with a custom primary key
```
## Test Plan
I wrote new Markdown test and also verified all of our assertions
against Django's runtime behavior.
ty ecosystem comments currently require downloading a ZIP to view the full reports. Add an optional `upload-html` mode to the shared report publisher and enable it for ty, linking directly to the diagnostic diff and timing results while retaining the downloadable artifact. The publisher runs from `main`, uses STS for GitHub credentials, and obtains temporary AWS upload credentials through GitHub OIDC when hosting is enabled. Each caller supplies filenames and content types, with optional link labels. The publisher reads only those files from a bounded archive without extracting or executing them during publication, and stores reports under separate paths for each PR, report, run, and attempt. If an upload fails, the publisher still attempts to post the summary and, when available, the artifact link. The `automations` environment requires `REPORTS_BUCKET`, `REPORTS_URL`, `REPORTS_ROLE_ARN`, and `REPORTS_REGION` from the report hosting infrastructure. --------- Co-authored-by: Zanie Blue <2586601+zanieb@users.noreply.github.com> Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Report comments include a redundant ZIP download link after the hosted HTML links. Show the ZIP link only when the HTML report is unavailable, including when its upload fails. Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
## Summary
This PR adds support for the `get_<field>_display()` methods that Django
generates for model fields with `choices`.
Example:
```py
from django.db import models
class Article(models.Model):
status = models.CharField(
max_length=1,
choices=[("D", "Draft"), ("P", "Published")],
)
article = Article(status="P")
reveal_type(article.status) # str
reveal_type(article.get_status_display()) # str ("Published" at runtime)
```
Towards astral-sh/ty#1018.
## Test Plan
New Markdown test.
Summary -- This addresses the suggestion from [#29635]. `DisplayDiagnosticConfig` previously determined the `DiagnosticFormat` for diagnostics coming from both Ruff and ty, which meant that it had to have a shared enum between the two, despite each program supporting a different subset of the available formats. This PR eliminates the shared `DiagnosticFormat` and dispatch through `DisplayDiagnostics`, leaving Ruff and ty to construct `Renderer`s directly and do their own dispatch on the output formats they actually support. This will be especially helpful in #29635, where we want to provide slightly different arguments to each new `SarifRenderer`. The `Renderer` trait itself isn't strictly necessary, but it made the calls on the Ruff side a lot neater since the trait provides a default `write` method based on the required `render` method. Codex also threw in a default `display` method that helps in a couple of places too. Test Plan -- Existing tests [#29635]: astral-sh/ruff#29635 (comment)
…29653)
## Summary
This PR adds support for the `get_next_by_<field>()` and
`get_previous_by_<field>()` methods that Django generates for
(non-`null=True`) `DateField` and `DateTimeField` fields.
Example:
```py
from django.db import models
class Article(models.Model):
published = models.DateField()
def _(article: Article):
reveal_type(article.get_next_by_published()) # Article
reveal_type(article.get_previous_by_published()) # Article
```
Towards astral-sh/ty#1018.
## Test Plan
New Markdown tests.
…664)
## Summary
This PR adds support for the `<field>_id` attributes that Django
generates for foreign keys. Their types follow the related model's
primary key, or the field specified by `to_field`.
Example:
```py
from django.db import models
class Author(models.Model):
pass
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
def _(book: Book):
reveal_type(book.author) # Author
reveal_type(book.author_id) # int
```
Towards astral-sh/ty#1018.
## Test Plan
New Markdown tests. I checked against Django runtime behavior.
The bottom signature is trivially assignable _to_, and the top signature is trivially assignable _from_, all other signatures. We can add fast path checks for those before performing more complex signature comparisons.
Handle `bot:ai-policy-comment` and `bot:ai-policy-close` on issues and pull requests with the shared `ai-policy` action. The automation dispatcher runs `ai-policy.yml` on `main`, where an STS-issued `astral-automations-bot` token posts the policy reminder and optionally closes the target. Draft and fork PRs are supported. The workflow checks the current label and state without checking out PR code. Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
## Summary We scan ASCII identifier continuations in sixteen-byte batches using a byte lookup table, avoiding per-character decoding. Keyword lookup filters by length and initial byte, then uses a compact hash table with a full-word comparison to reject collisions. Non-ASCII suffixes retain the existing Unicode path.
## Summary We give ASCII identifiers a dedicated path, avoiding Unicode bookkeeping and checking string prefixes only when a one- or two-letter name reaches a quote. Both paths share the existing batched ASCII scanner, preserving fast scanning for Unicode names with long ASCII suffixes. Stacked on #29463 to measure the incremental improvement. [CodSpeed reports](https://github.com/astral-sh/ruff/pull/29503/checks?check_run_id=118300735426) 6.6–9.8% greater efficiency across all five lexer benchmarks, with no reported regressions. We preserve the existing scanner and add no inlining attributes or unsafe code.
6db7be1 to
e0b10f1
Compare
ecosystem checkLinter (stable)ℹ️ ecosystem check detected linter changes. (+320 -231 violations, +0 -8 fixes in 27 projects; 1 project error; 30 projects unchanged) DisnakeDev/disnake (+34 -0 violations, +0 -0 fixes)
+ disnake/activity.py:5:8: ICN001 `datetime` should be imported as `dt` + disnake/audit_logs.py:35:12: ICN001 `datetime` should be imported as `dt` + disnake/automod.py:5:8: ICN001 `datetime` should be imported as `dt` + disnake/channel.py:6:8: ICN001 `datetime` should be imported as `dt` + disnake/embeds.py:5:8: ICN001 `datetime` should be imported as `dt` + disnake/entitlement.py:5:8: ICN001 `datetime` should be imported as `dt` + disnake/ext/commands/base_core.py:6:8: ICN001 `datetime` should be imported as `dt` + disnake/ext/commands/core.py:6:8: ICN001 `datetime` should be imported as `dt` + disnake/ext/tasks/__init__.py:6:8: ICN001 `datetime` should be imported as `dt` + disnake/guild.py:6:8: ICN001 `datetime` should be imported as `dt` ... 24 additional changes omitted for project RasaHQ/rasa (+9 -0 violations, +0 -0 fixes)
+ rasa/core/brokers/kafka.py:95:111: RUF100 [*] Unused `noqa` directive (unused: `E501`) + rasa/core/channels/hangouts.py:219:113: RUF100 [*] Unused `noqa` directive (unused: `E501`) + rasa/core/channels/hangouts.py:274:98: RUF100 [*] Unused `noqa` directive (unused: `E501`) + rasa/core/channels/hangouts.py:275:92: RUF100 [*] Unused `noqa` directive (unused: `E501`) + rasa/core/channels/mattermost.py:94:95: RUF100 [*] Unused `noqa` directive (unused: `E501`) + rasa/shared/nlu/training_data/formats/luis.py:39:92: RUF100 [*] Unused `noqa` directive (unused: `E501`) + tests/core/channels/test_hangouts.py:37:104: RUF100 [*] Unused `noqa` directive (unused: `E501`) + tests/core/channels/test_hangouts.py:54:108: RUF100 [*] Unused `noqa` directive (unused: `E501`) + tests/core/channels/test_hangouts.py:67:97: RUF100 [*] Unused `noqa` directive (unused: `E501`) apache/superset (+17 -0 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --no-preview --select ALL
+ superset/common/utils/dataframe_utils.py:19:8: ICN001 `datetime` should be imported as `dt` + superset/config.py:1261:88: RUF100 [*] Unused `noqa` directive (unused: `E501`) + superset/config.py:2425:115: RUF100 [*] Unused `noqa` directive (unused: `E501`) + superset/extensions/metadb.py:41:8: ICN001 `datetime` should be imported as `dt` + superset/mcp_service/system/tool/generate_bug_report.py:29:8: ICN001 `datetime` should be imported as `dt` + superset/mcp_service/system/tool/health_check.py:20:8: ICN001 `datetime` should be imported as `dt` + superset/migrations/versions/2018-07-05_15-19_3dda56f1c4c6_migrate_num_period_compare_and_period_.py:27:8: ICN001 `datetime` should be imported as `dt` + superset/result_set.py:19:8: ICN001 `datetime` should be imported as `dt` ... 10 additional changes omitted for rule ICN001 ... 9 additional changes omitted for project binary-husky/gpt_academic (+2 -34 violations, +0 -0 fixes)
- crazy_functions/Academic_Conversation.py:162:28: DTZ005 `datetime.datetime.now()` called without a `tz` argument - crazy_functions/Paper_Reading.py:239:17: DTZ005 `datetime.datetime.now()` called without a `tz` argument - crazy_functions/doc_fns/AI_review_doc.py:170:47: DTZ005 `datetime.datetime.now()` called without a `tz` argument - crazy_functions/doc_fns/batch_file_query_doc.py:170:47: DTZ005 `datetime.datetime.now()` called without a `tz` argument - crazy_functions/doc_fns/conversation_doc/excel_doc.py:102:42: DTZ005 `datetime.datetime.now()` called without a `tz` argument - crazy_functions/doc_fns/conversation_doc/txt_doc.py:54:20: DTZ005 `datetime.datetime.now()` called without a `tz` argument ... 26 additional changes omitted for rule DTZ005 - crazy_functions/doc_fns/text_content_loader.py:235:31: DTZ006 `datetime.datetime.fromtimestamp()` called without a `tz` argument - crazy_functions/高级功能函数模板.py:51:25: DTZ011 `datetime.date.today()` used - crazy_functions/高级功能函数模板.py:52:23: DTZ011 `datetime.date.today()` used + shared_utils/fastapi_stream_server.py:327:32: UP041 [*] Replace aliased errors with `TimeoutError` ... 26 additional changes omitted for project bokeh/bokeh (+15 -5 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --no-preview --select ALL
+ examples/server/app/weather/main.py:10:8: ICN001 `datetime` should be imported as `dt` + scripts/milestone.py:4:8: ICN001 `datetime` should be imported as `dt` + src/bokeh/_types.pyi:9:8: ICN001 `datetime` should be imported as `dt` + src/bokeh/core/property/datetime.py:24:8: ICN001 `datetime` should be imported as `dt` + src/bokeh/core/property/visual.py:25:8: ICN001 `datetime` should be imported as `dt` + src/bokeh/core/property/visual.pyi:19:4: PYI002 `if` test in a stub file must be a simple comparison against `sys.platform` or `sys.version_info` - src/bokeh/core/property/visual.pyi:19:4: PYI002 `if` test must be a simple comparison against `sys.platform` or `sys.version_info` + src/bokeh/models/plots.pyi:52:4: PYI002 `if` test in a stub file must be a simple comparison against `sys.platform` or `sys.version_info` - src/bokeh/models/plots.pyi:52:4: PYI002 `if` test must be a simple comparison against `sys.platform` or `sys.version_info` + src/bokeh/models/sources.pyi:22:4: PYI002 `if` test in a stub file must be a simple comparison against `sys.platform` or `sys.version_info` ... 10 additional changes omitted for project docker/docker-py (+0 -5 violations, +0 -0 fixes)
- docs/conf.py:60:8: DTZ005 `datetime.datetime.now()` called without a `tz` argument - tests/integration/api_container_test.py:975:54: DTZ005 `datetime.datetime.now()` called without a `tz` argument - tests/integration/client_test.py:38:17: DTZ005 `datetime.datetime.now()` called without a `tz` argument - tests/integration/client_test.py:48:25: DTZ005 `datetime.datetime.now()` called without a `tz` argument - tests/unit/client_test.py:29:17: DTZ001 `datetime.datetime()` called without a `tzinfo` argument fronzbot/blinkpy (+0 -0 violations, +0 -0 fixes)
ibis-project/ibis (+35 -0 violations, +0 -0 fixes)
+ ibis/backends/bigquery/tests/system/test_client.py:4:8: ICN001 `datetime` should be imported as `dt` + ibis/backends/bigquery/tests/unit/test_compiler.py:3:8: ICN001 `datetime` should be imported as `dt` + ibis/backends/clickhouse/converter.py:4:8: ICN001 `datetime` should be imported as `dt` + ibis/backends/exasol/__init__.py:4:8: ICN001 `datetime` should be imported as `dt` + ibis/backends/exasol/converter.py:3:8: ICN001 `datetime` should be imported as `dt` + ibis/backends/flink/utils.py:3:8: ICN001 `datetime` should be imported as `dt` + ibis/backends/impala/tests/test_client.py:3:8: ICN001 `datetime` should be imported as `dt` + ibis/backends/mssql/__init__.py:6:8: ICN001 `datetime` should be imported as `dt` + ibis/backends/polars/compiler.py:4:8: ICN001 `datetime` should be imported as `dt` + ibis/backends/pyspark/converter.py:3:8: ICN001 `datetime` should be imported as `dt` ... 25 additional changes omitted for project jrnl-org/jrnl (+6 -0 violations, +0 -0 fixes)
+ jrnl/journals/DayOneJournal.py:5:8: ICN001 `datetime` should be imported as `dt` + jrnl/journals/Entry.py:4:8: ICN001 `datetime` should be imported as `dt` + jrnl/journals/Journal.py:4:8: ICN001 `datetime` should be imported as `dt` + jrnl/time.py:4:8: ICN001 `datetime` should be imported as `dt` + tests/unit/test_journals_folder_journal.py:4:8: ICN001 `datetime` should be imported as `dt` + tests/unit/test_time.py:4:8: ICN001 `datetime` should be imported as `dt` langchain-ai/langchain (+13 -1 violations, +0 -0 fixes)
+ .github/scripts/check_diff.py:16:1: I001 [*] Import block is un-sorted or un-formatted - .github/scripts/check_extras_sync.py:9:1: I001 [*] Import block is un-sorted or un-formatted + .github/scripts/check_prerelease_dependencies.py:3:1: I001 [*] Import block is un-sorted or un-formatted + .github/scripts/get_min_versions.py:6:4: UP036 Version block is outdated for minimum Python version + libs/core/langchain_core/document_loaders/langsmith.py:3:8: ICN001 `datetime` should be imported as `dt` + libs/core/langchain_core/tracers/evaluation.py:59:46: RUF012 Mutable default value for class attribute + libs/core/langchain_core/utils/utils.py:4:8: ICN001 `datetime` should be imported as `dt` + libs/core/tests/unit_tests/document_loaders/test_langsmith.py:1:8: ICN001 `datetime` should be imported as `dt` + libs/langchain/langchain_classic/chains/query_constructor/parser.py:1:8: ICN001 `datetime` should be imported as `dt` + libs/langchain/langchain_classic/retrievers/time_weighted_retriever.py:1:8: ICN001 `datetime` should be imported as `dt` ... 4 additional changes omitted for project latchbio/latch (+3 -0 violations, +0 -0 fixes)
+ docs/source/conf.py:9:8: ICN001 `datetime` should be imported as `dt` + src/latch/registry/record.py:3:8: ICN001 `datetime` should be imported as `dt` + src/latch/resources/tasks.py:27:8: ICN001 `datetime` should be imported as `dt` lnbits/lnbits (+0 -0 violations, +0 -0 fixes)
milvus-io/pymilvus (+14 -0 violations, +0 -0 fixes)
+ examples/bulk_import/bulk_writer_all_types.py:1:8: ICN001 `datetime` should be imported as `dt` + examples/timestamptz.py:3:8: ICN001 `datetime` should be imported as `dt` + examples/timestamptz_insert.py:3:8: ICN001 `datetime` should be imported as `dt` + examples/timestamptz_meta.py:3:8: ICN001 `datetime` should be imported as `dt` + examples/timestamptz_search_query.py:3:8: ICN001 `datetime` should be imported as `dt` + pymilvus/client/check.py:1:8: ICN001 `datetime` should be imported as `dt` + pymilvus/client/iterator/query_iterator.py:3:8: ICN001 `datetime` should be imported as `dt` + pymilvus/client/prepare.py:2:8: ICN001 `datetime` should be imported as `dt` + pymilvus/client/ts_utils.py:1:8: ICN001 `datetime` should be imported as `dt` + pymilvus/client/utils.py:1:8: ICN001 `datetime` should be imported as `dt` ... 4 additional changes omitted for project ... Truncated remaining completed project reports due to GitHub comment length restrictions apache/airflow (error)
ruff check --no-cache --exit-zero --no-fix --output-format concise --no-preview --select ALL
Changes by rule (20 rules affected)
Linter (preview)ℹ️ ecosystem check detected linter changes. (+878 -189 violations, +0 -0 fixes in 33 projects; 1 project error; 24 projects unchanged) DisnakeDev/disnake (+34 -15 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
+ disnake/activity.py:5:8: unconventional-import-alias `datetime` should be imported as `dt` + disnake/audit_logs.py:35:12: unconventional-import-alias `datetime` should be imported as `dt` + disnake/automod.py:5:8: unconventional-import-alias `datetime` should be imported as `dt` + disnake/channel.py:6:8: unconventional-import-alias `datetime` should be imported as `dt` + disnake/embeds.py:5:8: unconventional-import-alias `datetime` should be imported as `dt` + disnake/entitlement.py:5:8: unconventional-import-alias `datetime` should be imported as `dt` ... 29 additional changes omitted for rule unconventional-import-alias - disnake/enums.py:751:33: multiple-spaces-before-keyword [*] Multiple spaces before keyword - disnake/enums.py:752:41: multiple-spaces-before-keyword [*] Multiple spaces before keyword - disnake/enums.py:753:32: multiple-spaces-before-keyword [*] Multiple spaces before keyword - disnake/enums.py:754:34: multiple-spaces-before-keyword [*] Multiple spaces before keyword ... 39 additional changes omitted for project PlasmaPy/PlasmaPy (+3 -12 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
+ .github/scripts/citation_updater.py:66:29: unnecessary-regular-expression-compile Compiled regular expression is used only once - src/plasmapy/formulary/quantum.py:123:10: float-equality-comparison Unreliable floating point equality comparison `0 * u.m / u.s == V` - tests/formulary/test_fusion.py:326:16: float-equality-comparison Unreliable floating point equality comparison `sigma.unit == u.m**3 / u.s` - tests/formulary/test_fusion.py:430:16: float-equality-comparison Unreliable floating point equality comparison `sv.unit == u.m**3 / u.s` - tests/formulary/test_fusion.py:451:16: float-equality-comparison Unreliable floating point equality comparison `sv.unit == u.m**3 / u.s` - tests/formulary/test_laser.py:89:12: float-equality-comparison Unreliable floating point equality comparison `result.unit == u.Watt / u.m**2` + tests/formulary/test_lengths.py:104:15: math-constant Replace `3.14159` with `math.pi` - tests/formulary/test_lengths.py:104:15: math-constant [*] Replace `3.14159` with `math.pi` - tests/formulary/test_misc.py:131:12: float-equality-comparison Unreliable floating point equality comparison `(Bohm_diffusion(T_e, B)).unit == u.m**2 / u.s` ... 5 additional changes omitted for rule float-equality-comparison + tests/particles/test_exceptions.py:304:13: math-constant Replace `3.14159` with `math.pi` ... 5 additional changes omitted for project apache/superset (+103 -15 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL
+ superset/commands/deletion_retention/purge_cascade.py:73:62: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager + superset/commands/importers/v1/utils.py:394:66: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager + superset/common/utils/dataframe_utils.py:19:8: unconventional-import-alias `datetime` should be imported as `dt` + superset/config.py:2453:6: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager + superset/distributed_lock/__init__.py:33:6: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager + superset/extensions/context.py:103:51: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager + superset/extensions/context.py:122:46: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager ... 68 additional changes omitted for rule context-manager-iterator + superset/extensions/metadb.py:41:8: unconventional-import-alias `datetime` should be imported as `dt` + superset/mcp_service/chart/tool/get_chart_preview.py:1127:44: math-constant Replace `6.28` with `math.tau` - superset/mcp_service/chart/tool/get_chart_preview.py:1127:44: math-constant [*] Replace `6.28` with `math.tau` ... 108 additional changes omitted for project binary-husky/gpt_academic (+11 -9 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
- crazy_functions/Audio_Assistant.py:24:32: strip-with-multi-characters Using `.strip()` with multi-character strings is misleading + crazy_functions/Audio_Assistant.py:24:34: strip-with-multi-characters Using `.strip()` with multi-character strings is misleading - crazy_functions/Latex_Function.py:465:18: strip-with-multi-characters Using `.strip()` with multi-character strings is misleading + crazy_functions/Latex_Function.py:465:27: strip-with-multi-characters Using `.lstrip()` with multi-character strings is misleading - request_llms/bridge_moss.py:236:32: strip-with-multi-characters Using `.strip()` with multi-character strings is misleading + request_llms/bridge_moss.py:236:41: strip-with-multi-characters Using `.strip()` with multi-character strings is misleading ... 13 additional changes omitted for rule strip-with-multi-characters + shared_utils/fastapi_stream_server.py:327:32: timeout-error-alias [*] Replace aliased errors with `TimeoutError` + shared_utils/fastapi_stream_server.py:371:32: timeout-error-alias [*] Replace aliased errors with `TimeoutError` ... 12 additional changes omitted for project bokeh/bokeh (+25 -10 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL
- examples/server/app/surface3d/surface3d.py:13:16: multiple-spaces-before-keyword [*] Multiple spaces before keyword + examples/server/app/weather/main.py:10:8: unconventional-import-alias `datetime` should be imported as `dt` + scripts/milestone.py:4:8: unconventional-import-alias `datetime` should be imported as `dt` + src/bokeh/_types.pyi:9:8: unconventional-import-alias `datetime` should be imported as `dt` + src/bokeh/core/property/datetime.py:24:8: unconventional-import-alias `datetime` should be imported as `dt` + src/bokeh/core/property/visual.py:25:8: unconventional-import-alias `datetime` should be imported as `dt` + src/bokeh/core/property/visual.pyi:19:4: complex-if-statement-in-stub `if` test in a stub file must be a simple comparison against `sys.platform` or `sys.version_info` - src/bokeh/core/property/visual.pyi:19:4: complex-if-statement-in-stub `if` test must be a simple comparison against `sys.platform` or `sys.version_info` + src/bokeh/io/util.py:137:19: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager + src/bokeh/io/util.py:216:67: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager ... 25 additional changes omitted for project facebookresearch/chameleon (+2 -0 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
+ chameleon/viewer/backend/data_types.py:17:7: replace-str-enum Class WSMessageType inherits from both `str` and `enum.Enum` + chameleon/viewer/backend/data_types.py:28:7: replace-str-enum Class ContentType inherits from both `str` and `enum.Enum` ibis-project/ibis (+73 -36 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
+ ibis/backends/_adbc.py:15:51: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager + ibis/backends/bigquery/tests/system/test_client.py:4:8: unconventional-import-alias `datetime` should be imported as `dt` + ibis/backends/bigquery/tests/unit/test_compiler.py:3:8: unconventional-import-alias `datetime` should be imported as `dt` + ibis/backends/clickhouse/converter.py:4:8: unconventional-import-alias `datetime` should be imported as `dt` + ibis/backends/clickhouse/tests/test_functions.py:120:50: math-constant Replace `3.14` with `math.pi` - ibis/backends/clickhouse/tests/test_functions.py:120:50: math-constant [*] Replace `3.14` with `math.pi` + ibis/backends/clickhouse/tests/test_functions.py:120:57: math-constant Replace `3.14` with `math.pi` - ibis/backends/clickhouse/tests/test_functions.py:120:57: math-constant [*] Replace `3.14` with `math.pi` + ibis/backends/exasol/__init__.py:4:8: unconventional-import-alias `datetime` should be imported as `dt` + ibis/backends/exasol/converter.py:3:8: unconventional-import-alias `datetime` should be imported as `dt` ... 99 additional changes omitted for project jrnl-org/jrnl (+6 -0 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
+ jrnl/journals/DayOneJournal.py:5:8: unconventional-import-alias `datetime` should be imported as `dt` + jrnl/journals/Entry.py:4:8: unconventional-import-alias `datetime` should be imported as `dt` + jrnl/journals/Journal.py:4:8: unconventional-import-alias `datetime` should be imported as `dt` + jrnl/time.py:4:8: unconventional-import-alias `datetime` should be imported as `dt` + tests/unit/test_journals_folder_journal.py:4:8: unconventional-import-alias `datetime` should be imported as `dt` + tests/unit/test_time.py:4:8: unconventional-import-alias `datetime` should be imported as `dt` langchain-ai/langchain (+42 -7 violations, +0 -0 fixes)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview
+ .github/scripts/check_diff.py:16:1: unsorted-imports [*] Import block is un-sorted or un-formatted - .github/scripts/check_extras_sync.py:9:1: unsorted-imports [*] Import block is un-sorted or un-formatted + .github/scripts/check_prerelease_dependencies.py:3:1: unsorted-imports [*] Import block is un-sorted or un-formatted + .github/scripts/get_min_versions.py:6:4: outdated-version-block Version block is outdated for minimum Python version + libs/core/langchain_core/document_loaders/langsmith.py:3:8: unconventional-import-alias `datetime` should be imported as `dt` + libs/core/langchain_core/tracers/evaluation.py:59:46: mutable-class-default Mutable default value for class attribute + libs/core/langchain_core/utils/utils.py:4:8: unconventional-import-alias `datetime` should be imported as `dt` + libs/core/langchain_core/utils/utils.py:74:46: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager + libs/core/tests/unit_tests/document_loaders/test_langsmith.py:1:8: unconventional-import-alias `datetime` should be imported as `dt` + libs/core/tests/unit_tests/language_models/chat_models/test_base.py:384:35: context-manager-iterator Use `Generator` instead of `Iterator` for a context manager ... 39 additional changes omitted for project ... Truncated remaining completed project reports due to GitHub comment length restrictions apache/airflow (error)
ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL
Changes by rule (21 rules affected)
Formatter (stable)ℹ️ ecosystem check detected format changes. (+152 -136 lines in 29 files in 3 projects; 1 project error; 54 projects unchanged) PlasmaPy/PlasmaPy (+1 -3 lines across 1 file)
src/plasmapy/formulary/braginskii.py~L371 self.m_i = m_i
self.Z = _grab_charge(ion, Z) * u.dimensionless_unscaled
if self.Z < 0:
- raise ValueError(
- "Z is not allowed to be negative!"
- ) # TODO: remove? # noqa: FIX002
+ raise ValueError("Z is not allowed to be negative!") # TODO: remove? # noqa: FIX002
# decide on the particle string for the electrons
self.e_particle = "e-"demisto/content (+3 -9 lines across 1 file)
return CommandResults(readable_output="Could not create IP named location")
-def azure_ad_identity_protection_confirm_compromised_command(
- ms_client: Client, args: dict
-) -> CommandResults: # pragma: no cover # noqa
+def azure_ad_identity_protection_confirm_compromised_command(ms_client: Client, args: dict) -> CommandResults: # pragma: no cover # noqa
user_ids = str(args.get("user_ids")).split(",")
data = {"userIds": user_ids}
try: return CommandResults(readable_output=f"Could not compromised {user_ids!s}:\n{e}")
-def azure_ad_identity_protection_risky_users_dismiss_command(
- ms_client: Client, args: dict
-) -> CommandResults: # pragma: no cover # noqa
+def azure_ad_identity_protection_risky_users_dismiss_command(ms_client: Client, args: dict) -> CommandResults: # pragma: no cover # noqa
user_ids = str(args.get("user_ids")).split(",")
data = {"userIds": user_ids}
try: return CommandResults(readable_output="could not list IP named locations")
-def azure_ad_identity_protection_risky_users_history_list(
- ms_client: Client, args: dict
-) -> CommandResults: # pragma: no cover # noqa
+def azure_ad_identity_protection_risky_users_history_list(ms_client: Client, args: dict) -> CommandResults: # pragma: no cover # noqa
limit = args.get("limit")
odata = args.get("odata_query")
user_id = args.get("user_id")rotki/rotki (+148 -124 lines across 27 files)
rotkehlchen/accounting/export/csv.py~L177
index = event.index + CSV_INDEX_OFFSET
value_formula = f"{amount_column}{index}*H{index}"
- total_value_formula = f"(F{index}*H{index}+G{index}*H{index})" # formula of both free and taxable # noqa: E501
+ total_value_formula = (
+ f"(F{index}*H{index}+G{index}*H{index})" # formula of both free and taxable # noqa: E501
+ )
cost_basis_column = "K" if name == "taxable" else "L"
cost_basis = f"{cost_basis_column}{index}"
rotkehlchen/chain/ethereum/airdrops.py~L157 """
api_url: str
- amount_path: str # json keys separated by `/` that point to the amount that needs to be extracted # noqa: E501
+ amount_path: (
+ str # json keys separated by `/` that point to the amount that needs to be extracted # noqa: E501
+ )
class AirdropClaimEventQueryParams(NamedTuple):rotkehlchen/chain/ethereum/modules/eigenlayer/decoder.py~L476 extra_data={"matched": True},
)
else:
- new_event = self.base.make_event_from_transaction( # so let's just keep minimal info # noqa: E501
- transaction=context.transaction,
- tx_log=context.tx_log,
- event_type=HistoryEventType.INFORMATIONAL,
- event_subtype=HistoryEventSubType.NONE,
- asset=A_ETH,
- amount=ZERO,
- location_label=context.transaction.from_address,
- notes=f"Complete eigenlayer withdrawal {withdrawal_root}",
- counterparty=CPT_EIGENLAYER,
- address=context.tx_log.address,
+ new_event = (
+ self.base.make_event_from_transaction( # so let's just keep minimal info # noqa: E501
+ transaction=context.transaction,
+ tx_log=context.tx_log,
+ event_type=HistoryEventType.INFORMATIONAL,
+ event_subtype=HistoryEventSubType.NONE,
+ asset=A_ETH,
+ amount=ZERO,
+ location_label=context.transaction.from_address,
+ notes=f"Complete eigenlayer withdrawal {withdrawal_root}",
+ counterparty=CPT_EIGENLAYER,
+ address=context.tx_log.address,
+ )
)
return EvmDecodingOutput(events=[new_event])rotkehlchen/chain/ethereum/modules/eigenlayer/decoder.py~L593 token=token,
)
notes = f"Withdraw {amount} {token.symbol} from Eigenlayer"
- for event in context.decoded_events: # pre-slashing contracts transfer before emitting the completion event # noqa: E501
+ for event in (
+ context.decoded_events
+ ): # pre-slashing contracts transfer before emitting the completion event # noqa: E501
if (
event.event_type == HistoryEventType.RECEIVE
and event.event_subtype == HistoryEventSubType.NONErotkehlchen/chain/ethereum/modules/gwei_names/decoder.py~L177 """
label, expires = decode_abi(["string", "uint256"], context.tx_log.data)
if expires == 0:
- return DEFAULT_EVM_DECODING_OUTPUT # subdomain. Handled in _decode_subdomain_registered # noqa: E501
+ return (
+ DEFAULT_EVM_DECODING_OUTPUT # subdomain. Handled in _decode_subdomain_registered # noqa: E501
+ )
fullname = f"{label}.gwei"
with GlobalDBHandler().conn.write_ctx() as write_cursor:rotkehlchen/chain/evm/decoding/decoder.py~L1314 if not self.base.any_tracked([owner_address, spender_address]):
return DEFAULT_EVM_DECODING_OUTPUT
- event = self.base.make_event_from_transaction( # notes are generated, see EvmEvent.auto_notes # noqa: E501
- transaction=transaction,
- tx_log=tx_log,
- event_type=HistoryEventType.INFORMATIONAL,
- event_subtype=HistoryEventSubType.APPROVE,
- asset=token,
- amount=token_normalized_value(token_amount=amount_raw, token=token),
- location_label=owner_address,
- address=spender_address,
+ event = (
+ self.base.make_event_from_transaction( # notes are generated, see EvmEvent.auto_notes # noqa: E501
+ transaction=transaction,
+ tx_log=tx_log,
+ event_type=HistoryEventType.INFORMATIONAL,
+ event_subtype=HistoryEventSubType.APPROVE,
+ asset=token,
+ amount=token_normalized_value(token_amount=amount_raw, token=token),
+ location_label=owner_address,
+ address=spender_address,
+ )
)
return EvmDecodingOutput(events=[event])
rotkehlchen/chain/evm/decoding/ens/decoder.py~L94 if transfer_event is None: # Can happen if neither from/to is tracked
return DEFAULT_EVM_DECODING_OUTPUT
- label_hash = f"0x{collectible_id:064x}" # Transform the int token id to a 32 bytes hex label hash # noqa: E501
+ label_hash = (
+ f"0x{collectible_id:064x}" # Transform the int token id to a 32 bytes hex label hash # noqa: E501
+ )
found_name = self._maybe_get_labelhash_name(context=context, label_hash=label_hash)
if found_name is None:
name_to_show = ""rotkehlchen/chain/evm/decoding/safe/decoder.py~L117 have too many events spamming if owners are added, removed etc."""
for event in context.decoded_events:
if event.counterparty == CPT_SAFE_MULTISIG and event.address == context.tx_log.address:
- return DEFAULT_EVM_DECODING_OUTPUT # only add if no other safe-specific events exist # noqa: E501
+ return (
+ DEFAULT_EVM_DECODING_OUTPUT # only add if no other safe-specific events exist # noqa: E501
+ )
if not self.base.any_tracked([context.transaction.from_address, context.tx_log.address]):
return DEFAULT_EVM_DECODING_OUTPUTrotkehlchen/chain/evm/decoding/superchain_bridge/l2/decoder.py~L206 )
break
else:
- return decoded_events # no tracked ETH transfer was decoded for this deposit transaction # noqa: E501
+ return (
+ decoded_events # no tracked ETH transfer was decoded for this deposit transaction # noqa: E501
+ )
return [
eventrotkehlchen/chain/solana/modules/stake/decoder.py~L114 is newly created (a transformed transfer is already in the decoded events), or
None when no funding by a tracked address is found.
"""
- for event in context.decoded_events: # a plain transfer funding the stake account has already been decoded as a spend # noqa: E501
+ for event in (
+ context.decoded_events
+ ): # a plain transfer funding the stake account has already been decoded as a spend # noqa: E501
if (
event.address == stake_account
and event.event_type == HistoryEventType.SPENDrotkehlchen/chain/solana/utils.py~L94
# Minimum size for an initialized stake account (state + Meta)
-STAKE_ACCOUNT_META_SIZE: Final = 124 # 4 (state) + 8 (rent_exempt) + 32 (staker) + 32 (withdrawer) + 8 + 8 + 32 (lockup) # noqa: E501
+STAKE_ACCOUNT_META_SIZE: Final = (
+ 124 # 4 (state) + 8 (rent_exempt) + 32 (staker) + 32 (withdrawer) + 8 + 8 + 32 (lockup) # noqa: E501
+)
# Size including delegation data
STAKE_ACCOUNT_DELEGATED_SIZE: Final = (
196 # Meta(124) + Delegation(32 + 8 + 8 + 8 + 8) + credits_observed(8) # noqa: E501rotkehlchen/data_migrations/migrations/migration_20.py~L268 for row in cursor:
spend, receive = get_swap_spend_receive_v47_48(
is_buy=row[4]
- in {
- "A",
- "C",
- }, # A/C = buy/settlement buy; B,D = sell/settlement sell # noqa: E501
+ in {"A", "C"}, # A/C = buy/settlement buy; B,D = sell/settlement sell # noqa: E501
base_asset=Asset(row[2]),
quote_asset=Asset(row[3]),
amount=FVal(row[5]),rotkehlchen/db/drivers/sqlite.py~L52 type UnderlyingCursor = rsqlite.Cursor | sqlcipher.Cursor # pylint: disable=no-member
type UnderlyingConnection = rsqlite.Connection | sqlcipher.Connection # pylint: disable=no-member
-CONTEXT_SWITCH_WAIT = 0.025 # seconds between cancellation checks while waiting for the transaction slot # noqa: E501
+CONTEXT_SWITCH_WAIT = (
+ 0.025 # seconds between cancellation checks while waiting for the transaction slot # noqa: E501
+)
# Rows a cursor prefetches per statement_lock acquisition when iterated. Iteration
# is the hot row-consumption path (~1650 ca
_report truncated to fit GitHub's comment size limit; see the `ecosystem-result` artifact of the run for the full text._ |
by ecosystem round-tripbase: regressions: 3, changed: 1254, improvements: 3, error changes: 0 (across 31551 files in 149 projects) ❌ regressions (built on base, now fails)jax —kopf —scipy —ℹ️ changed round-trip outputExpression — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -174,5 +174,5 @@
"/tmp/tmptr_66v43/Expression/build/tests/test_option_builder.py": {"by": "sha256:7840a4f57784d2ef311a2ef18c79b209a034eac6bfb5df8337f90d250e373987", "py": "sha256:0de7554008625d8560ae4eb0682547226ac1091be046962e4e39108e1411c484"},
"/tmp/tmptr_66v43/Expression/build/tests/test_parser.py": {"by": "sha256:39577ecb356a7f3b4158c49f8c060dfc9cd0142128c6af15f95b7f422dfc605b", "py": "sha256:8e4aefd4d1ee28dd4d0da4df7e832d03522ac3a44a8406ff866f091c528ab97a"},
- "/tmp/tmptr_66v43/Expression/build/tests/test_pipe.py": {"by": "sha256:dccc0720a422704d70137f01c446c7271f1e9c6b616020c0d4ba6030f4121120", "py": "sha256:2dbef997f2ecd1ebe6f21f8fa435feefb5b8f0fb5934e16fe779468adc98554c"},
+ "/tmp/tmptr_66v43/Expression/build/tests/test_pipe.py": {"by": "sha256:dccc0720a422704d70137f01c446c7271f1e9c6b616020c0d4ba6030f4121120", "py": "sha256:813a73ac91621947d88dc450bf0f173d257c36eb6d29066bc8220140b9aff5bc"},
"/tmp/tmptr_66v43/Expression/build/tests/test_result.py": {"by": "sha256:6e5e956b69fde7ce2117abd740cd468e49d379c604b2acd100c61d75a240c610", "py": "sha256:1d34e2859d6d75364eaa62659f3b195628d4461c54248e203a7f5f02631ff7d7"},
"/tmp/tmptr_66v43/Expression/build/tests/test_result_builder.py": {"by": "sha256:4079a8bdf4aac52cc8667e3bbc363c65367597b1c54b49ffd0fabf287a91c519", "py": "sha256:31ce4b1874b967f46a9926bb1b2a6c8f8ed149fcf3d130cfc8ceda89e12b325c"},Expression — tests/test_pipe.py--- base/tests/test_pipe.py
+++ head/tests/test_pipe.py
@@ -139,5 +139,5 @@
def test_starpipe_simple():
- assert _soundness_check(starpipe((1, 2), fn), tuple) == _soundness_check(fn(1, 2), tuple)
+ assert starpipe((1, 2), fn) == _soundness_check(fn(1, 2), tuple)PyGithub — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -515,5 +515,5 @@
"/tmp/tmphxkhcjpc/PyGithub/build/openapi/conftest.py": {"by": "sha256:b7b3ce9254deaa83ee4787b0ee0511658b3a0d1aec5321906f0c6e3dc323dc38", "py": "sha256:d3a19b3f9de87d52196b54d6b4ab1467a3601a020a1e46ddbc1ce708e18dbee4"},
"/tmp/tmphxkhcjpc/PyGithub/build/scripts/fix_headers.py": {"by": "sha256:105094085c5acc16071f1de2451593a71500faa1ed75d5af681744f7732b0a38", "py": "sha256:a5ea5c1cde206ab6e3c70137dc404a0f57f3f195da8ed3d616884dafd2d90915"},
- "/tmp/tmphxkhcjpc/PyGithub/build/scripts/openapi.py": {"by": "sha256:6b7d3d9508920c13f91e4dd5f6cff52b5293f5eb927e1dbe22ca8243a48df925", "py": "sha256:cd1b4404f1a88641ff2a530a40d1762ee22481f189711953c54679ef11765c99"},
+ "/tmp/tmphxkhcjpc/PyGithub/build/scripts/openapi.py": {"by": "sha256:6b7d3d9508920c13f91e4dd5f6cff52b5293f5eb927e1dbe22ca8243a48df925", "py": "sha256:ebfccf9b54622e889f90d778b946e5e17eb20ebd5f52795570615d59a99cd0df"},
"/tmp/tmphxkhcjpc/PyGithub/build/scripts/prepare-for-update-assertions.py": {"by": "sha256:dd1f8c58c01073da2d1c925f9ba265e4909ac9b3e6a2541b593af5b9cde3c906", "py": "sha256:08f68b18dd974244f15cb23c240fbb847e2bd6ada1140deb67a5c093b9fb9837"},
"/tmp/tmphxkhcjpc/PyGithub/build/scripts/sort_class.py": {"by": "sha256:0b97be6db4fc1e7ec55d925d5ddb6e5f686522b4b43360ab51ce1808153ddec4", "py": "sha256:dbc4b082c54d1f7f237218ae45b1afd3c88294db47bc67b9139d77d504dcb433"},PyGithub — scripts/openapi.py--- base/scripts/openapi.py
+++ head/scripts/openapi.py
@@ -190,5 +190,5 @@
return GithubClass(**classes.get(class_name))
if verbose:
- for class_name in _soundness_iter(classes, str):
+ for class_name in classes:
if class_name not in classes:
print(f"Class not found in index: {class_name}")Tanjun — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -136,5 +136,5 @@
"/tmp/tmpt84dtb2m/Tanjun/build/tanjun/context/message.py": {"by": "sha256:be1728bd9288183fde8e43248bbd5c7a2d04309caa3a0bb46a20873fcb20316e", "py": "sha256:b7d747a3be937ca356315920833e6f0b90b582b242828b388f05eea8e35f8813"},
"/tmp/tmpt84dtb2m/Tanjun/build/tanjun/context/slash.py": {"by": "sha256:550220ec90ff87af79bf4dd8f0e65461d5069994a9e850f83542895d70e491c0", "py": "sha256:040ede5e92eed7df3e616519fd6159b8256b6df42f1300f5db17fc311dd74758"},
- "/tmp/tmpt84dtb2m/Tanjun/build/tanjun/conversion.py": {"by": "sha256:872b6ab8fe53724088dcd06b15129f65494c859552997829eaa7dce7152ceef2", "py": "sha256:67bf5196e32ce645600a30b7607ba94d0930c68981fda11712f7e58411aed1b8"},
+ "/tmp/tmpt84dtb2m/Tanjun/build/tanjun/conversion.py": {"by": "sha256:872b6ab8fe53724088dcd06b15129f65494c859552997829eaa7dce7152ceef2", "py": "sha256:77aaa56f619e4e380923531367b23aeb21f05d1a90a4958d2bc5b56fcba95fd3"},
... 2788 characters elided ...
"/tmp/tmpt84dtb2m/Tanjun/build/tests/test_utilities.py": {"by": "sha256:77bbddada1803c358aa6a20c89e455a374df73e8621ee90315c3ab077cca62dd", "py": "sha256:90b7de842db371c4f16353419b40466ab81749193701d9e26edb6b48a3eb194e"},
}Tanjun — tanjun/conversion.py--- base/tanjun/conversion.py
+++ head/tanjun/conversion.py
@@ -1302,6 +1302,6 @@
capture = next(_MESSAGE_LINK_REGEX.finditer(value), None)
if capture:
- channel_id = hikari.Snowflake(capture[2])
- message_id = hikari.Snowflake(capture[3])
+ channel_id = hikari.Snowflake(_soundness_check(capture[2], str))
+ message_id = hikari.Snowflake(_soundness_check(capture[3], str))
# We should also range check the provided ID.Tanjun — tanjun/dependencies/reloaders.py--- base/tanjun/dependencies/reloaders.py
+++ head/tanjun/dependencies/reloaders.py
@@ -515,5 +515,5 @@
raise FileNotFoundError(error_message)
- return directory.resolve(), (namespace, set()) if namespace is None else (namespace, set())
+ return directory.resolve(), (namespace, set()) if namespace is None else (namespace, set[str]())Tanjun — tests/test_schedules.py--- base/tests/test_schedules.py
+++ head/tests/test_schedules.py
@@ -568,7 +568,7 @@
assert interval._task is None
assert interval._tasks == []
- assert _soundness_check(mock_task_1.cancelled(), bool) is True
- assert _soundness_check(mock_task_2.cancelled(), bool) is True
- assert _soundness_check(mock_task_3.cancelled(), bool) is True
+ assert mock_task_1.cancelled() is True
+ assert mock_task_2.cancelled() is True
+ assert mock_task_3.cancelled() is True
mock_client.call_with_async_di.assert_not_called()
@@ -726,7 +726,7 @@
assert interval._tasks == []
assert mock_task_1.result() is None
- assert _soundness_check(mock_task_2.cancelled(), bool) is True
+ assert mock_task_2.cancelled() is True
assert mock_task_3.result() is None
- assert _soundness_check(mock_task_4.cancelled(), bool) is True
+ assert mock_task_4.cancelled() is True
mock_client.call_with_async_di.assert_not_called()
@@ -1151,7 +1151,7 @@
assert interval.is_alive is False
... 555 characters elided ...
- assert _soundness_check(mock_task_1.cancelled(), bool) is True
+ assert mock_task_1.cancelled() is True
assert mock_task_2.result() is None
- assert _soundness_check(mock_task_3.cancelled(), bool) is True
+ assert mock_task_3.cancelled() is True
assert mock_task_4.result() is Noneaiohttp — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -180,7 +180,7 @@
DIGESTS = {
"/tmp/tmptb1k9t6q/aiohttp/build/aiohttp/__init__.py": {"by": "sha256:d29745d55a831a6a2731f10386a32710b24232ab24e95b389f6f4f6a0df2b242", "py": "sha256:a1c2bb9b08e719e7054662e147a2712f80c5633955b5ac8da574d8ac4ebbd33c"},
- "/tmp/tmptb1k9t6q/aiohttp/build/aiohttp/_cookie_helpers.py": {"by": "sha256:ce04d777a848bea4dfd15c515dbb4da02bb06870f354328c29f6cb33acf70a40", "py": "sha256:76883ff72a0113a4c4642a292da833e18568fd9123a5a28434675e2f623ff337"},
+ "/tmp/tmptb1k9t6q/aiohttp/build/aiohttp/_cookie_helpers.py": {"by": "sha256:ce04d777a848bea4dfd15c515dbb4da02bb06870f354328c29f6cb33acf70a40", "py": "sha256:ce4be4abe3201ac794868fcd33101429911750b485209a943a58c4cdd1de9cda"},
"/tmp/tmptb1k9t6q/aiohttp/build/aiohttp/_websocket/__init__.py": {"by": "sha256:31aaf747dfef04dfc46b896c5bb8930155c3ece2acc0a3c6a85e71812cadefb9", "py": "sha256:31aaf747dfef04dfc46b896c5bb8930155c3ece2acc0a3c6a85e71812cadefb9"},
... 10586 characters elided ...
"/tmp/tmptb1k9t6q/aiohttp/build/tests/test_web_exceptions.py": {"by": "sha256:3e4e2971ad7c5dbeec4de619934ab2a52939ac839a16d060341765ba8c7d7471", "py": "sha256:cc1419cb995ab85a7fef4cbaa266bbb5323c7a704e4099e2720db4ae23f814cd"},aiohttp — aiohttp/_cookie_helpers.py--- base/aiohttp/_cookie_helpers.py
+++ head/aiohttp/_cookie_helpers.py
@@ -244,7 +244,7 @@
continue
- key = match.group("key")
- value = match.group("val") or ""
- i = match.end(0)
+ key = _soundness_check(match.group("key"), str)
+ value = _soundness_check(match.group("val"), (str, type(None))) or ""
+ i = _soundness_check(match.end(0), int)
# Validate the nameaiohttp — aiohttp/_websocket/helpers.py--- base/aiohttp/_websocket/helpers.py
+++ head/aiohttp/_websocket/helpers.py
@@ -95,6 +95,6 @@
# Server never fail to detect compress handshake.
# Server does not need to send max wbit to client
- if match.group(4):
- compress = int(match.group(4))
+ if _soundness_check(match.group(4), (str, type(None))):
+ compress = int(_soundness_check(match.group(4), (str, type(None))))
# Group3 must match if group4 matches
# Compress wbit 8 does not support in zlib
@@ -104,11 +104,11 @@
compress = 0
continue
- if match.group(1):
+ if _soundness_check(match.group(1), (str, type(None))):
notakeover = True
# Ignore regex group 5 & 6 for client_max_window_bits
break
else:
- if match.group(6):
- compress = int(match.group(6))
+ if _soundness_check(match.group(6), (str, type(None))):
... 288 characters elided ...
raise WSHandshakeError("Invalid window size")
- if match.group(2):
+ if _soundness_check(match.group(2), (str, type(None))):
notakeover = True
# Ignore regex group 5 & 6 for client_max_window_bitsaiohttp — aiohttp/client_middleware_digest_auth.py--- base/aiohttp/client_middleware_digest_auth.py
+++ head/aiohttp/client_middleware_digest_auth.py
@@ -258,9 +258,9 @@
)
- qop_raw = challenge.get("qop", "")
+ qop_raw = _soundness_check(challenge.get("qop", ""), str)
# Preserve original algorithm case for response while using uppercase for processing
- algorithm_original = challenge.get("algorithm", "MD5")
+ algorithm_original = _soundness_check(challenge.get("algorithm", "MD5"), str)
algorithm = algorithm_original.upper()
- opaque = challenge.get("opaque", "")
+ opaque = _soundness_check(challenge.get("opaque", ""), str)
# Convert string values to bytes once
@@ -446,5 +446,5 @@
self._protection_space = []
- if domain := self._challenge.get("domain"):
+ if domain := _soundness_check(self._challenge.get("domain"), (str, type(None))):
# Parse space-separated list of URIs
for uri in _soundness_iter(domain.split(), str):aiohttp — aiohttp/cookiejar.py--- base/aiohttp/cookiejar.py
+++ head/aiohttp/cookiejar.py
@@ -506,5 +506,5 @@
elif copy_morsels:
# TODO(https://github.com/python/typeshed/pull/16346): Remove cast
- cookie = _soundness_parametric(cast(Morsel[str], _soundness_check(cookie.copy(), dict)), Morsel[str], (0,))
+ cookie = _soundness_parametric(cast(Morsel[str], _soundness_check(cookie.copy(), Morsel)), Morsel[str], (0,))
domain = cookie["domain"]
@@ -835,5 +835,5 @@
if day_match:
found_day = True
- day = int(day_match.group())
+ day = int(_soundness_check(day_match.group(), str))
continue
@@ -850,5 +850,5 @@
if year_match:
found_year = True
- year = int(year_match.group())
+ year = int(_soundness_check(year_match.group(), str))
if 70 <= year <= 99:aiohttp — aiohttp/web_protocol.py--- base/aiohttp/web_protocol.py
+++ head/aiohttp/web_protocol.py
@@ -281,5 +281,5 @@
self._lingering_time = float(lingering_time)
- self._messages: deque[_MsgType] = deque()
+ self._messages: deque[_MsgType] = deque[tuple[RawRequestMessage | _ErrInfo, StreamReader]]()
self._message_tail = b""
self._data_received_cb: Callable2[[], None] | None = Noneaiohttp — tests/test_http_parser.py--- base/tests/test_http_parser.py
+++ head/tests/test_http_parser.py
@@ -265,5 +265,5 @@
messages, upgrade, tail = parser.feed_data(text)
assert len(messages) == 1
- msg = messages[0][0]
+ msg = _soundness_check(messages[0], tuple)[0]
assert list[tuple[str, str]](msg.headers.items()) == [
@@ -424,5 +424,5 @@
messages, _, _ = parser.feed_data(b"st: a\r\n\r\n")
assert len(messages) == 1
- assert messages[0][0].path == "/split"
+ assert _soundness_check(messages[0], tuple)[0].path == "/split"
@@ -537,5 +537,5 @@
text = f"POST / HTTP/1.1\r\nHost: a\r\n{headers}\r\n\r\n".encode()
messages, upgrade, tail = parser.feed_data(text)
- msg = messages[0][0]
+ msg = _soundness_check(messages[0], tuple)[0]
assert msg.headers.getall("Foo") == expected
@@ -753,5 +753,5 @@
text = b"GET / HTTP/1.1\r\nHost: a\r\ntest: \t value \t \r\n\r\n"
messages, upgrade, tail = parser.feed_data(text)
- msg = messages[0][0]
+ msg = _soundness_check(messages[0], tuple)[0]
assert msg.headers["test"] == "value"
@@ -776,5 +776,5 @@
... 30730 characters elided ...
assert msg.path == quote("/путь?ключ=знач#фраг", safe="/?=#")
@@ -3049,5 +3049,5 @@
text = b"GET /path?#frag HTTP/1.1\r\nHost: a\r\n\r\n"
messages, upgrade, tail = parser.feed_data(text)
- msg = messages[0][0]
+ msg = _soundness_check(messages[0], tuple)[0]
assert msg.url.path == "/path"aiohttp — tests/test_multipart.py--- base/tests/test_multipart.py
+++ head/tests/test_multipart.py
@@ -1760,7 +1760,7 @@
if isinstance(part, aiohttp.BodyPartReader):
if part.headers[CONTENT_TYPE] == "application/json":
- assert _soundness_check(next(idata), (dict, int, bytes)) == (await part.json())
+ assert next(idata) == (await part.json())
else:
- assert _soundness_check(next(idata), (dict, int, bytes)) == await part.read(decode=True)
+ assert next(idata) == await part.read(decode=True)
else:
await check(part)aiohttp — tests/test_run_app.py--- base/tests/test_run_app.py
+++ head/tests/test_run_app.py
@@ -837,5 +837,5 @@
assert proc.stdout.readline().startswith(b"======== Running on") # type: ignore[union-attr]
proc.send_signal(signal.SIGINT)
- assert _soundness_check(proc.wait(), int) == 0
+ assert proc.wait() == 0
@@ -852,5 +852,5 @@
assert proc.stdout.readline().startswith(b"======== Running on") # type: ignore[union-attr]
proc.terminate()
- assert _soundness_check(proc.wait(), int) == 0
+ assert proc.wait() == 0aiohttp — tests/test_streams.py--- base/tests/test_streams.py
+++ head/tests/test_streams.py
@@ -1738,5 +1738,5 @@
line_iter = iter(DATA.splitlines(keepends=True))
async for line in await create_stream():
- assert line == _soundness_check(next(line_iter, None), (bytes, type(None)))
+ assert line == next(line_iter, None)
pytest.raises(StopIteration, next, line_iter)
@@ -1747,5 +1747,5 @@
chunk_iter = chunkify(DATA, 9)
async for data in _soundness_aiter((await create_stream()).iter_chunked(9), bytes):
- assert data == _soundness_check(next(chunk_iter, None), (Sequence, type(None)))
+ assert data == next(chunk_iter, None)
pytest.raises(StopIteration, next, chunk_iter)
@@ -1755,5 +1755,5 @@
chunk_iter = chunkify(DATA, 8)
async for data in _soundness_aiter((await create_stream()).iter_chunked(8), bytes):
- assert data == _soundness_check(next(chunk_iter, None), (Sequence, type(None)))
+ assert data == next(chunk_iter, None)
pytest.raises(StopIteration, next, chunk_iter)
@@ -1781,5 +1781,5 @@
item_iter = iter(items)
async for item in buffer:
- assert item is _soundness_check(next(item_iter, None), (str, type(None)))
+ assert item is next(item_iter, None)
pytest.raises(StopIteration, next, item_iter)aiohttp — tests/test_web_app.py--- base/tests/test_web_app.py
+++ head/tests/test_web_app.py
@@ -188,7 +188,7 @@
key = web.AppKey[int]("key", int)
app = web.Application()
- assert _soundness_check(app.get(key, "foo"), (int, str)) == "foo"
+ assert app.get(key, "foo") == "foo"
app[key] = 5
- assert _soundness_check(app.get(key, "foo"), (int, str)) == 5
+ assert app.get(key, "foo") == 5aiohttp-devtools — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -35,5 +35,5 @@
"/tmp/tmpjv9u8e67/aiohttp-devtools/build/aiohttp_devtools/cli.py": {"by": "sha256:4344a08cb73fb6e8d539031e6e51fd060e38ee0b996351540bda2c8e19e48e4f", "py": "sha256:f158fa573674f74fbc906fa5ac87c87ac2e492024699f11b3644793225ecd469"},
"/tmp/tmpjv9u8e67/aiohttp-devtools/build/aiohttp_devtools/exceptions.py": {"by": "sha256:7a18b495b8286f306530bb430f5c574d9e11e8af6e23979adac9046076a075a2", "py": "sha256:7a18b495b8286f306530bb430f5c574d9e11e8af6e23979adac9046076a075a2"},
- "/tmp/tmpjv9u8e67/aiohttp-devtools/build/aiohttp_devtools/logs.py": {"by": "sha256:1ee64aff1ad7f71466e395e40df5a86c2586752fcc5005f81ca4a548d58dddbb", "py": "sha256:8e01743e68c97701c5a0e1123824be68d5e0c021fd92ee43a9b88a04d9f4db96"},
+ "/tmp/tmpjv9u8e67/aiohttp-devtools/build/aiohttp_devtools/logs.py": {"by": "sha256:1ee64aff1ad7f71466e395e40df5a86c2586752fcc5005f81ca4a548d58dddbb", "py": "sha256:a75f51901d1a7f1cc8d91dbfabd62d53c6ee517094a79c6c02d1713f35e3bd4e"},
... 252 characters elided ...
"/tmp/tmpjv9u8e67/aiohttp-devtools/build/aiohttp_devtools/runserver/config.py": {"by": "sha256:c44008ce961b71c0ad818076124279d8cf28df4abd2a2b024a765ebd4f105cb8", "py": "sha256:b1d568fb9b0be5ee832a97065a4d22a640cd899f6c59370096aa68145b7e92a9"},aiohttp-devtools — aiohttp_devtools/logs.py--- base/aiohttp_devtools/logs.py
+++ head/aiohttp_devtools/logs.py
@@ -48,5 +48,5 @@
if m:
time = sformat(_soundness_check(_soundness_check(m.groups(), tuple)[0], str), sformat.magenta)
- return time + sformat(msg[m.end():], log_color)
+ return time + sformat(msg[_soundness_check(m.end(), int):], log_color)
return sformat(msg, log_color)aiortc — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -93,5 +93,5 @@
"/tmp/tmpg_01e4dt/aiortc/build/aiortc/codecs/g711.py": {"by": "sha256:db8e03b010baa67d88455577bb8bdae4257e5141f9e77cf23d1459d7a3e17b1d", "py": "sha256:caa02e468fe3dfb9297854d292aa2e3346335abc53717b156b1db2f5f68b5668"},
"/tmp/tmpg_01e4dt/aiortc/build/aiortc/codecs/g722.py": {"by": "sha256:148718999908305ad1add2222432c2eadb91417e625c7285b443e8968569d9d3", "py": "sha256:3dba07fb8a9233088d48ca07b6ae852420553778fbdf5420cbf89edb840f9e4c"},
- "/tmp/tmpg_01e4dt/aiortc/build/aiortc/codecs/h264.py": {"by": "sha256:20436a39e3f817de1e00ac7afe19f489bdc58d2af89f1301d2098855d1ddd98d", "py": "sha256:0eb48684cd38d780a0a918806b8c81af62350c425a470b473ee8efc6e0b6cccc"},
+ "/tmp/tmpg_01e4dt/aiortc/build/aiortc/codecs/h264.py": {"by": "sha256:20436a39e3f817de1e00ac7afe19f489bdc58d2af89f1301d2098855d1ddd98d", "py": "sha256:2b424ab8cb7614aa484e152878ab6af6a8e99622740e07a84878ed47b68797f1"},
... 1568 characters elided ...
"/tmp/tmpg_01e4dt/aiortc/build/aiortc/utils.py": {"by": "sha256:dd1e1b5678f972bcfb4ac2a6cf3f8eb223594aeab2d5df3cf37c49d52a244b80", "py": "sha256:d685d95fffcc76c8ad6f5f5c9266d4772122e11722edd27a45669a4bf8186f1e"},aiortc — aiortc/codecs/h264.py--- base/aiortc/codecs/h264.py
+++ head/aiortc/codecs/h264.py
@@ -236,9 +236,9 @@
packages_iterator = iter(packages)
- package = _soundness_check(next(packages_iterator, None), (bytes, type(None)))
+ package = next(packages_iterator, None)
while package is not None:
if len(package) > PACKET_MAX:
packetized_packages.extend(cls._packetize_fu_a(package))
- package = _soundness_check(next(packages_iterator, None), (bytes, type(None)))
+ package = next(packages_iterator, None)
else:
packetized, package = cls._packetize_stap_a(package, packages_iterator)aiortc — aiortc/sdp.py--- base/aiortc/sdp.py
+++ head/aiortc/sdp.py
@@ -155,5 +155,5 @@
m = re.match("^IN (IP4|IP6) ([^ ]+)$", sdp)
assert m
- return m.group(2)
+ return _soundness_check(m.group(2), str)
@@ -436,6 +436,6 @@
# check payload types are valid
- kind = m.group(1)
- fmt = m.group(4).split()
+ kind = _soundness_check(m.group(1), str)
+ fmt = _soundness_check(m.group(4), str).split()
fmt_int: Optional[list[int]] = None
if kind in ["audio", "video"]:
@@ -446,5 +446,5 @@
current_media = MediaDescription(
- kind=kind, port=int(m.group(2)), profile=m.group(3), fmt=fmt_int or fmt
+ kind=kind, port=int(_soundness_check(m.group(2), str)), profile=_soundness_check(m.group(3), str), fmt=fmt_int or fmt
)
current_media.dtls = RTCDtlsParameters(alectryon — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -56,7 +56,7 @@
"/tmp/tmptr_66v43/alectryon/build/alectryon/coqc_time.py": {"by": "sha256:7c602d50dcae85794e8ebe6eea452ba122d9a86a147c8db1cf71e938c6351767", "py": "sha256:48557a20b6e6a3194a2f8d104d01800b130f4571f86d13192de25ecdd0efd55b"},
"/tmp/tmptr_66v43/alectryon/build/alectryon/coqlsp.py": {"by": "sha256:1e6f77ad8a3ad07a68a36aa42eeda31a4283a3f1acc98ca81cf3a38b675b8aeb", "py": "sha256:185f14c04c64f62164126cefc0fa7750cd2f6f65adaf4c69bafc75131519b979"},
- "/tmp/tmptr_66v43/alectryon/build/alectryon/core.py": {"by": "sha256:3455231481c7be1768159f0b6a3f59a65756a2b1fb09b1bed388290caa3385a9", "py": "sha256:2ceed7436d3e62622e0852530a66d71cec13304b3a3442be2b843bc178679e25"},
+ "/tmp/tmptr_66v43/alectryon/build/alectryon/core.py": {"by": "sha256:3455231481c7be1768159f0b6a3f59a65756a2b1fb09b1bed388290caa3385a9", "py": "sha256:1a3b38b2fc27c10c4b0b718fbec4c162c12562b1e5b13b701d76dc6a378c4822"},
... 5893 characters elided ...
"/tmp/tmptr_66v43/alectryon/build/alectryon.py": {"by": "sha256:680ba7e0bde5cb9c6013a55fae72d531ca4ffde71b728fff0144b1c02fac1d92", "py": "sha256:f434bc20127819411bc5b534f91eeab563baf816ba3723664a0ce355bdcd0dc8"},alectryon — alectryon/core.py--- base/alectryon/core.py
+++ head/alectryon/core.py
@@ -76,9 +76,9 @@
def measure_indentation(line):
m = INDENTATION_RE.match(line)
- return m.end() - m.start() if m else None
+ return _soundness_check(m.end(), int) - _soundness_check(m.start(), int) if m else None
def measure_min_indentation(lines):
indents = (measure_indentation(ln) for ln in lines)
- return min((i for i in _soundness_iter(indents, (int, type(None))) if i is not None), default=0)
+ return _soundness_check(min((i for i in _soundness_iter(indents, (int, type(None))) if i is not None), default=0), int)
def dedent(lines, amount):
@@ -1162,5 +1162,5 @@
for block in blocks:
if isinstance(block, CodeSnippet):
- block = _soundness_once_bound(("CodeSnippet",), must(_soundness_once_bound(("CodeSnippet",), next(it, None), _soundness_check, lambda: (CodeSnippet, type(None)))), _soundness_check, lambda: CodeSnippet)
+ block = must(next(it, None))
yield block
- assert _soundness_once_bound(("CodeSnippet",), next(it, None), _soundness_check, lambda: (CodeSnippet, type(None))) is None
+ assert next(it, None) is Nonealectryon — alectryon/docutils.py--- base/alectryon/docutils.py
+++ head/alectryon/docutils.py
@@ -1049,5 +1049,5 @@
mid = COQ_ID_RE.match(text)
assert mid
- title, target = mid.group("title"), mid.group("target")
+ title, target = _soundness_check(mid.group("title"), str), _soundness_check(mid.group("target"), (str, type(None)))
return title, targetalectryon — alectryon/literate.py--- base/alectryon/literate.py
+++ head/alectryon/literate.py
@@ -365,5 +365,5 @@
expected = _soundness_check(self.TRANSITIONS[state], tuple)
raise ParsingError(self.doc, state, expected, start, token_end)
- tok, mstart, self.pos = Token(m.lastgroup), m.start(), m.end()
+ tok, mstart, self.pos = Token(m.lastgroup), _soundness_check(m.start(), int), _soundness_check(m.end(), int)
if not self.step(state, start, tok, mstart):
break
@@ -476,5 +476,5 @@
class CoqParser(BlockParser):
- TRANSITIONS: dict[State, tuple[Token, Token, Token] | tuple[Token, Token]] = {
+ TRANSITIONS: dict[State, tuple[Token, ...]] = {
State.CODE: (Token.COMMENT_OPEN,
Token.STRING_DELIM,
@@ -566,5 +566,5 @@
# TODO: Add support for char (``'"'``) syntax
# TODO: Technically doc comments don't support nesting
- TRANSITIONS: dict[State, tuple[Token, Token, Token, Token] | tuple[Token, Token, Token] | tuple[Token] | tuple[Token, Token]] = {
+ TRANSITIONS: dict[State, tuple[Token, ...]] = {
State.CODE: (Token.LINE_COMMENT_OPEN,
Token.COMMENT_OPEN,alectryon — alectryon/lsp.py--- base/alectryon/lsp.py
+++ head/alectryon/lsp.py
@@ -65,5 +65,5 @@
header = LSPServerMessage.JRPC_HEADER_RE.match(line)
if header:
- length = int(header.group("len"))
+ length = int(_soundness_check(header.group("len"), str))
if line == "":alectryon — alectryon/markers.py--- base/alectryon/markers.py
+++ head/alectryon/markers.py
@@ -193,14 +193,14 @@
raise ParseError(path[start:])
for matcher_name, matcher in QUERY_MATCHERS.items():
- needle = m.group(matcher_name)
+ needle = _soundness_check(m.group(matcher_name), (str, type(None)))
if needle is not None:
- kind = m.group("kind")
+ kind = _soundness_check(m.group("kind"), (str, type(None)))
allowed_matchers = _soundness_check(QUERY_KINDS[kind], tuple)
if matcher_name not in allowed_matchers:
if matcher_name == "nil":
raise MissingPattern(kind, path[start:])
- raise UnsupportedPattern(m.group("search"), kind, path[start:])
+ raise UnsupportedPattern(_soundness_check(m.group("search"), (str, type(None))), kind, path[start:])
parsed[kind] = matcher(needle)
- start = m.end()
+ start = _soundness_check(m.end(), int)
return parsedalectryon — alectryon/sexp.py--- base/alectryon/sexp.py
+++ head/alectryon/sexp.py
@@ -99,5 +99,5 @@
stack = [sexp]
while stack:
- top = stack.pop()
+ top = _soundness_check(stack.pop(), int)
if isinstance(top, list):
buf.append(OPEN)alectryon — alectryon/transforms.py--- base/alectryon/transforms.py
+++ head/alectryon/transforms.py
@@ -867,6 +867,6 @@
m = LEAN_TRAILING_BLANKS_RE.search(contents)
if m:
- yield _replace_contents(fr, contents[:m.start()])
- fr = Text(contents[m.start():])
+ yield _replace_contents(fr, contents[:_soundness_check(m.start(), int)])
+ fr = Text(contents[_soundness_check(m.start(), int):])
yield fr
@@ -886,5 +886,5 @@
if m and not isinstance(grouped[idx - 1], Text):
prev = grouped[idx-1]
- comma, rest = fr.contents[:m.end()], fr.contents[m.end():]
+ comma, rest = fr.contents[:_soundness_check(m.end(), int)], fr.contents[_soundness_check(m.end(), int):]
grouped[idx-1] = _replace_contents(prev, _contents(prev) + comma)
grouped[idx] = Text(rest) if rest else Nonealectryon — alectryon/typst.py--- base/alectryon/typst.py
+++ head/alectryon/typst.py
@@ -271,5 +271,5 @@
# Typst labels come wrapped as ``<name>``
label = re.sub(r"\A<(.*)>\Z", r"\1", lbl) if (lbl := item.get("label")) else None
- return _soundness_check(TypstCodeSnippet.of_text(m.group(1), "", _soundness_check(text, str), src=text, label=label), TypstCodeSnippet)
+ return _soundness_check(TypstCodeSnippet.of_text(_soundness_check(m.group(1), str), "", _soundness_check(text, str), src=text, label=label), TypstCodeSnippet)
def _parse_query_output(self, items: Iterable[JSON], snippets: list[TypstCodeSnippet]) -> None:altair — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -54,5 +54,5 @@
"/tmp/tmpy177xswn/altair/build/altair/expr/__init__.py": {"by": "sha256:c0756990a9d8202b055eb3eb01dd3d4cdb6e3fbb227b4670c90d2efefcf34d64", "py": "sha256:20409b7ebbfd04c77ab58e829989ef8c76dfc2b65d77c258467f493afeede37a"},
"/tmp/tmpy177xswn/altair/build/altair/expr/consts.py": {"by": "sha256:4166f78ef96c438372a05b020b592a22c86f43b2895b99dd3c91e5d2aee5a1e0", "py": "sha256:4166f78ef96c438372a05b020b592a22c86f43b2895b99dd3c91e5d2aee5a1e0"},
- "/tmp/tmpy177xswn/altair/build/altair/expr/core.py": {"by": "sha256:fb1d69f063bd5b05e8a236f9ea7c8e5982bae6d040fc6b3d2cf6d1cededc4eee", "py": "sha256:6191784795c738e3df34361cb5db696c9d3dcb374a5d4afc5359be58e5d16c53"},
+ "/tmp/tmpy177xswn/altair/build/altair/expr/core.py": {"by": "sha256:fb1d69f063bd5b05e8a236f9ea7c8e5982bae6d040fc6b3d2cf6d1cededc4eee", "py": "sha256:a7b19edef139eedd4a11ab5cff815ec39961ca9c17a4fe011e3ecd7526e9b445"},
... 4612 characters elided ...
"/tmp/tmpy177xswn/altair/build/tools/versioning.py": {"by": "sha256:3a3e090ca3e25a1dcae6831047f836ea8c122584e068ed96834465aa450ad908", "py": "sha256:427eef115e540c970afe6873ca9a7a9e03ead80835a684b90ae675351c0b7967"},
}altair — altair/expr/core.py--- base/altair/expr/core.py
+++ head/altair/expr/core.py
@@ -221,5 +221,5 @@
"""
- _schema: dict[str, str] = {"type": "string"}
+ _schema = {"type": "string"}
def to_dict(self, *args, **kwargs):altair — altair/vegalite/v6/schema/core.py--- base/altair/vegalite/v6/schema/core.py
+++ head/altair/vegalite/v6/schema/core.py
@@ -3035,5 +3035,5 @@
"""Aggregate schema wrapper."""
- _schema: dict[str, str] = {"$ref": "#/definitions/Aggregate"}
+ _schema = {"$ref": "#/definitions/Aggregate"}
def __init__(self, *args, **kwds):
@@ -3044,5 +3044,5 @@
"""AggregateOp schema wrapper."""
- _schema: dict[str, str] = {"$ref": "#/definitions/AggregateOp"}
+ _schema = {"$ref": "#/definitions/AggregateOp"}
def __init__(self, *args):
@@ -3067,5 +3067,5 @@
"""
- _schema: dict[str, str] = {"$ref": "#/definitions/AggregatedFieldDef"}
+ _schema = {"$ref": "#/definitions/AggregatedFieldDef"}
def __init__(
@@ -3085,5 +3085,5 @@
"""Align schema wrapper."""
- _schema: dict[str, str] = {"$ref": "#/definitions/Align"}
+ _schema = {"$ref": "#/definitions/Align"}
def __init__(self, *args):
@@ -3094,5 +3094,5 @@
"""AnyMark schema wrapper."""
- _schema: dict[str, str] = {"$ref": "#/definitions/AnyMark"}
+ _schema = {"$ref": "#/definitions/AnyMark"}
... 97191 characters elided ...
+ _schema = {"$ref": "#/definitions/WindowOnlyOp"}
def __init__(self, *args):
@@ -35528,5 +35528,5 @@
"""
- _schema: dict[str, str] = {"$ref": "#/definitions/WindowTransform"}
+ _schema = {"$ref": "#/definitions/WindowTransform"}
def __init__(altair — altair/vegalite/v6/schema/mixins.py--- base/altair/vegalite/v6/schema/mixins.py
+++ head/altair/vegalite/v6/schema/mixins.py
@@ -607,5 +607,5 @@
"""
- _schema: dict[str, str] = {"$ref": "#/definitions/MarkDef"}
+ _schema = {"$ref": "#/definitions/MarkDef"}
def __init__(
@@ -1071,5 +1071,5 @@
"""
- _schema: dict[str, str] = {"$ref": "#/definitions/BoxPlotDef"}
+ _schema = {"$ref": "#/definitions/BoxPlotDef"}
def __init__(
@@ -1175,5 +1175,5 @@
"""
- _schema: dict[str, str] = {"$ref": "#/definitions/ErrorBarDef"}
+ _schema = {"$ref": "#/definitions/ErrorBarDef"}
def __init__(
@@ -1287,5 +1287,5 @@
"""
- _schema: dict[str, str] = {"$ref": "#/definitions/ErrorBandDef"}
+ _schema = {"$ref": "#/definitions/ErrorBandDef"}
def __init__(altair — tools/datasets/datapackage.py--- base/tools/datasets/datapackage.py
+++ head/tools/datasets/datapackage.py
@@ -104,5 +104,5 @@
_soundness_check(rsrc["name"], str): {_soundness_check(f["name"], str): _soundness_check(f["type"], str) for f in _soundness_iter(s["fields"], dict)}
for rsrc in _soundness_iter(self._resources, dict)
- if (s := rsrc.get("schema"))
+ if (s := _soundness_check(rsrc.get("schema"), (dict, type(None))))
}
return maltair — tools/vega_expr.py--- base/tools/vega_expr.py
+++ head/tools/vega_expr.py
@@ -823,5 +823,5 @@
and (child := next(iter(children)).get(RAW) is not None)
and (match := FUNCTION_DEF_LINE.match(child))
- and (node := cls(match["name"], children)).is_callable()
+ and (node := cls(_soundness_check(match["name"], (str, type(None))), children)).is_callable()
):
yield node.with_parameters().with_signature()antidote — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -134,5 +134,5 @@
"/tmp/tmpt84dtb2m/antidote/build/antidote/lib/lazy_ext/__init__.py": {"by": "sha256:42d59e0fed76ba6ce17ded2affd9fef1ee926e443fbb2a8c61e8783fff565e8c", "py": "sha256:2c267fa0ec3807c453223a6fcb91ee7d28afae73d9c33c7bc1254ac9e8d5494a"},
"/tmp/tmpt84dtb2m/antidote/build/antidote/lib/lazy_ext/_const.py": {"by": "sha256:2d56c8b857a107f5eca18bbc12358ad067b81a90fc2fa77c5b84dbdb55bdb583", "py": "sha256:36b249222b3abc09de8325326debd816738d7239aea31b6d90e2b495caa9488b"},
- "/tmp/tmpt84dtb2m/antidote/build/antidote/lib/lazy_ext/_lazy.py": {"by": "sha256:7478fa9c191f38bcff021fec098dd0365e7cce770821043a9453a2145197e14c", "py": "sha256:04dad5ff55d53d56debfe52224794b146fb7b61bede13685f1b842d254b03e2c"},
+ "/tmp/tmpt84dtb2m/antidote/build/antidote/lib/lazy_ext/_lazy.py": {"by": "sha256:7478fa9c191f38bcff021fec098dd0365e7cce770821043a9453a2145197e14c", "py": "sha256:3ba661e34365d375b57ecd0be3f8ad01729c572976f0bc13aa56f344dd99190e"},
"/tmp/tmpt84dtb2m/antidote/build/antidote/lib/lazy_ext/_provider.py": {"by": "sha256:04af321174bee59902ba9fe3c1768c098a79bb9fd60af8f47746e2345bb1386c", "py": "sha256:2b1f9d80e9b35307e4916173134b0c674064b7a6c7479c149460d2b1693106a1"},
"/tmp/tmpt84dtb2m/antidote/build/tests/__init__.py": {"by": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "py": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},antidote — antidote/lib/lazy_ext/_lazy.py--- base/antidote/lib/lazy_ext/_lazy.py
+++ head/antidote/lib/lazy_ext/_lazy.py
@@ -205,5 +205,5 @@
else:
assert _kind is FunctionKind.VALUE
- return LazyValue(
+ return LazyValue[object](
wrapped=wrapped,
injected=injected,anyio — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -25,5 +25,5 @@
"/tmp/tmptb1k9t6q/anyio/build/anyio/abc/_resources.py": ("/tmp/tmptb1k9t6q/anyio/src/anyio/abc/_resources.by", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36]),
"/tmp/tmptb1k9t6q/anyio/build/anyio/abc/_subprocesses.py": ("/tmp/tmptb1k9t6q/anyio/src/anyio/abc/_subprocesses.by", [None, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 14, 14, 14, 14, 14, 19, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 29, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 39, 40, 40, 41, 41, 41, 41, 41, 41, 41, 48, 49, 50, 50, 51, 52, 53, 54, 54, 55, 55, 55, 55, 59, 60, 61, 61, 62, 63, 64, 65, 65, 66, 67, 68, 69, 69, 70]),
... 11985 characters elided ...
"/tmp/tmptb1k9t6q/anyio/build/tests/test_to_process.py": {"by": "sha256:1643b91289e468965d77eb4788681e960688a807d2e9db576f12fb6358e9a84c", "py": "sha256:75843a72830a9f49d841c90eaaa838e9e6c2d3316552565d326881ab3b3e5947"},anyio — anyio/_core/_concurrency_utils.py--- base/anyio/_core/_concurrency_utils.py
+++ head/anyio/_core/_concurrency_utils.py
@@ -90,5 +90,5 @@
handles: list[TaskHandle[Any]] = []
async with create_task_group() as tg:
- handles.extend(_soundness_check(tg.create_task(coro), TaskHandle) for coro in _soundness_iter(coros, Coroutine))
+ handles.extend(_soundness_check(tg.create_task(coro), TaskHandle) for coro in coros)
return tuple(h.return_value for h in _soundness_iter(handles, TaskHandle))anyio — anyio/_core/_eventloop.py--- base/anyio/_core/_eventloop.py
+++ head/anyio/_core/_eventloop.py
@@ -226,5 +226,5 @@
else:
try:
- return sniffio.current_async_library()
+ return _soundness_check(sniffio.current_async_library(), (str, type(None)))
except sniffio.AsyncLibraryNotFoundError:
pass
@@ -238,5 +238,5 @@
return None
- return sniffio.current_async_library_cvar.set(asynclib_name)
+ return _soundness_check(sniffio.current_async_library_cvar.set(asynclib_name), (Token, type(None)))anyio — anyio/abc/_tasks.py--- base/anyio/abc/_tasks.py
+++ head/anyio/abc/_tasks.py
@@ -1,3 +1,2 @@
-from anyio._by_runtime import _soundness_check
lazy import sys
@@ -157,5 +156,5 @@
"""
final_name = get_callable_name(func, name)
- return self.create_task(_soundness_check(call_for_coroutine(func, args), Coroutine), name=final_name)
+ return self.create_task(call_for_coroutine(func, args), name=final_name)
@overloadanyio — tests/test_from_thread.py--- base/tests/test_from_thread.py
+++ head/tests/test_from_thread.py
@@ -175,5 +175,5 @@
assert result == 3
finally:
- await _soundness_check(gen.aclose(), Coroutine)
+ await gen.aclose()
async def test_run_sync_from_thread(self) -> None:
@@ -387,5 +387,5 @@
assert result == 3
finally:
- await _soundness_check(gen.aclose(), Coroutine)
+ await gen.aclose()
async def test_aexit_with_exception(self) -> None:anyio — tests/test_taskgroups.py--- base/tests/test_taskgroups.py
+++ head/tests/test_taskgroups.py
@@ -1085,7 +1085,7 @@
try:
loop = asyncio.get_running_loop()
- await loop.create_task(_soundness_check(host_agen.__anext__(), Coroutine))
+ await loop.create_task(host_agen.__anext__())
finally:
- await _soundness_check(host_agen.aclose(), Coroutine)
+ await host_agen.aclose()
assert doneanyio — tests/test_tempfile.py--- base/tests/test_tempfile.py
+++ head/tests/test_tempfile.py
@@ -175,5 +175,5 @@
async def test_cancellation_during_creation(self) -> None:
original = tempfile.TemporaryDirectory
- manager = TemporaryDirectory()
+ manager = TemporaryDirectory[str]()
paths: list[pathlib.Path] = []
@@ -252,5 +252,5 @@
cancellation is still delivered to the caller afterwards.\
"""
- td = TemporaryDirectory()
+ td = TemporaryDirectory[str]()
async with td as td_str:
td_path = pathlib.Path(td_str)apprise — _by_sourcemap.py--- base/_by_sourcemap.py
+++ head/_by_sourcemap.py
@@ -9,5 +9,5 @@
"/tmp/tmpjv9u8e67/apprise/build/apprise/attachment/__init__.py": ("/tmp/tmpjv9u8e67/apprise/apprise/attachment/__init__.by", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38]),
... 153172 characters elided ...
"/tmp/tmpjv9u8e67/apprise/build/tests/test_plugin_zalo.py": {"by": "sha256:7bd4aa54026e400758fbce9b43b6716b70f030a1ca63342911ca85a86e64df90", "py": "sha256:6db3ee8863ffec5805bcc71e6e5299275720cb286f18fb41cec40f02fda09332"},apprise — apprise/attachment/file.py--- base/apprise/attachment/file.py
+++ head/apprise/attachment/file.py
@@ -1,2 +1,3 @@
+from apprise._by_runtime import _soundness_check
# BSD 2-Clause License
#
@@ -141,4 +142,4 @@
return None
- results["path"] = AttachFile.unquote(match.group("path"))
+ results["path"] = AttachFile.unquote(_soundness_check(match.group("path"), str))
return resultsapprise — apprise/attachment/http.py--- base/apprise/attachment/http.py
+++ head/apprise/attachment/http.py
@@ -226,5 +226,5 @@
)
if result:
- self.detected_name = result.group("name").strip()
+ self.detected_name = _soundness_check(result.group("name"), str).strip()
# Keep the file on Windows; __del__ cleans it up.apprise — apprise/attachment/memory.py--- base/apprise/attachment/memory.py
+++ head/apprise/attachment/memory.py
@@ -199,5 +199,5 @@
# Store our filename only (ignore any defined paths)
results["name"] = _soundness_check(os.path.basename(
- AttachMemory.unquote(match.group("path"))
+ AttachMemory.unquote(_soundness_check(match.group("path"), str))
), str)
return resultsapprise — apprise/config/base.py--- base/apprise/config/base.py
+++ head/apprise/config/base.py
@@ -573,5 +573,5 @@
# Attempt to detect configuration
- if result.group("yaml"):
+ if _soundness_check(result.group("yaml"), (str, type(None))):
config_format = common.ConfigFormat.YAML
ConfigBase.logger.debug(
@@ -580,5 +580,5 @@
break
- elif result.group("text") or result.group("assign"):
+ elif _soundness_check(result.group("text"), (str, type(None))) or _soundness_check(result.group("assign"), (str, type(None))):
config_format = common.ConfigFormat.TEXT
ConfigBase.logger.debug(
@@ -724,7 +724,7 @@
# Retrieve our line
url, assign, config = (
- result.group("url"),
- result.group("assign"),
- result.group("config"),
+ _soundness_check(result.group("url"), (str, type(None))),
+ _soundness_check(result.group("assign"), (str, type(None))),
... 813 characters elided ...
@@ -1711,5 +1711,5 @@
# URL Processing
#
- for entry in _soundness_iter(preloaded, dict):
+ for entry in preloaded:
# Point to our results entry for easier reference below
results = entry["results"]apprise — apprise/config/file.py--- base/apprise/config/file.py
+++ head/apprise/config/file.py
@@ -1,2 +1,3 @@
+from apprise._by_runtime import _soundness_check
# BSD 2-Clause License
#
@@ -169,4 +170,4 @@
return None
- results["path"] = ConfigFile.unquote(match.group("path"))
+ results["path"] = ConfigFile.unquote(_soundness_check(match.group("path"), str))
return resultsapprise — apprise/conversion/commonmark.py--- base/apprise/conversion/commonmark.py
+++ head/apprise/conversion/commonmark.py
@@ -129,5 +129,5 @@
"""
m = _HTML_BLOCK_START_RE.match(line)
- if m and m.group("cdata") and m.group("cdata") != "<![CDATA[":
+ if m and _soundness_check(m.group("cdata"), (str, type(None))) and _soundness_check(m.group("cdata"), (str, type(None))) != "<![CDATA[":
return None
return m
@@ -396,6 +396,6 @@
if not m:
return None
- marker_end = pos + m.end()
- marker_col = col + _text_width(m.group(0), col)
+ marker_end = pos + _soundness_check(m.end(), int)
+ marker_col = col + _text_width(_soundness_check(m.group(0), str), col)
rest = line[marker_end:]
@@ -450,10 +450,10 @@
"""
if not quote_depth:
- if _leading_width(line) >= list_width:
+ if _soundness_check(_leading_width(line), int) >= list_width:
return _chars_for_width(line, list_width)
return None
# List-then-quote.
- if _leading_width(line) >= list_width:
+ if _soundness_check(_leading_width(line), int) >= list_width:
... 3886 characters elided ...
for marker in payload["consumed_markers"]:
- working_pending[marker] = _soundness_check(working_pending.get(marker, 0), int) - 1
+ working_pending[marker] = working_pending.get(marker, 0) - 1
else:
out.append(payload)apprise — apprise/conversion/html.py--- base/apprise/conversion/html.py
+++ head/apprise/conversion/html.py
@@ -1089,5 +1089,5 @@
if ordered:
# Escape just the '.', not the digits themselves
- dot = ordered.end() - 1
+ dot = _soundness_check(ordered.end(), int) - 1
return content[:dot] + "\\" + content[dot:]
@@ -1197,5 +1197,5 @@
if tag == "ol":
# Read an optional starting number from ordered lists.
- start_attr = _soundness_check(next((v for k, v in attrs if k == "start"), None), (str, type(None)))
+ start_attr = next((v for k, v in attrs if k == "start"), None)
if start_attr is not None:
with contextlib.suppress(TypeError, ValueError):
@@ -1235,5 +1235,5 @@
if _soundness_check(ctx["list_type"], (type(None), int, str)) == "ol" and _soundness_check(ctx["counter"], (type(None), int, str)) is not None:
# Read an optional per-item numbering override.
... 724 characters elided ...
if (
scheme
- and scheme.group(1).lower() in self._UNSAFE_HREF_SCHEMES
+ and _soundness_check(scheme.group(1), str).lower() in self._UNSAFE_HREF_SCHEMES
):
# Preserve link shape while neutralizing unsafe targets.apprise — apprise/decorators/base.py--- base/apprise/decorators/base.py
+++ head/apprise/decorators/base.py
@@ -115,7 +115,7 @@
# Acquire our schema
- schema = re_match.group("schema").lower()
-
- if not re_match.group("base"):
+ schema = _soundness_check(re_match.group("schema"), str).lower()
+
+ if not _soundness_check(re_match.group("base"), (str, type(None))):
url = f"{schema}://"
@@ -159,5 +159,5 @@
)
- requirements: dict[str, str] = {
+ requirements = {
# Define our required packaging in order to work
"details": f"Source: {inspect.getfile(send_func)}"
@@ -168,5 +168,5 @@
# Update our default arguments
- _base_args: None | dict[str, None | str | dict[Never, Never]] | dict[Never, Never] = base_args
+ _base_args: None | dict[str, None | str | dict[Never, Never]] = base_args
def __init__(self, **kwargs):apprise — apprise/locale.py--- base/apprise/locale.py
+++ head/apprise/locale.py
@@ -257,11 +257,11 @@
result = AppriseLocale._local_re.match(entry)
- if not result or not result.group("lang"):
+ if not result or not _soundness_check(result.group("lang"), (str, type(None))):
# The value is not a supported language format.
return None
# Language codes are lower case, regions are upper case (en_CA)
- language = result.group("lang").lower()
- country = result.group("country")
+ language = _soundness_check(result.group("lang"), (str, type(None))).lower()
+ country = _soundness_check(result.group("country"), (str, type(None)))
# Drop unsupported regions or script names such as Hans in zh-Hans.
@@ -279,5 +279,5 @@
# C, POSIX, and C.UTF-8 all mean the same thing here
result = AppriseLocale._local_re.match(value)
- return bool(result and result.group("ansii"))
+ return bool(result and _soundness_check(result.group("ansii"), (str, type(None))))
@staticmethodapprise — apprise/manager.py--- base/apprise/manager.py
+++ head/apprise/manager.py
@@ -206,5 +206,5 @@
# Store our notification/plugin name:
- module_name = match.group("name")
+ module_name = _soundness_check(match.group("name"), str)
module_pyname = f"{module_name_prefix}.{module_name}"
@@ -464,5 +464,5 @@
re_match = module_re.match(os.path.basename(path))
# must be a match and must have a .py extension
- if not re_match or not re_match.group(1):
+ if not re_match or not _soundness_check(re_match.group(1), (str, type(None))):
# keep going
logger.trace("Plugin Scan: Ignoring %s", path)apprise — apprise/persistent_store.py--- base/apprise/persistent_store.py
+++ head/apprise/persistent_store.py
@@ -301,5 +301,5 @@
return str(self) == str(other)
- return self.__value == other
+ return _soundness_check(self.__value == other, bool)
def __str__(self) -> str:
@@ -1767,6 +1767,6 @@
if not result
else (
- result["key"]
- if self.__valid_key.fullmatch(result["key"])
+ _soundness_check(result["key"], (str, type(None)))
+ if self.__valid_key.fullmatch(_soundness_check(result["key"], (str, type(None))))
else None
)
@@ -1791,6 +1791,6 @@
if not result
else (
- result["key"]
- if self.__valid_key.fullmatch(result["key"])
+ _soundness_check(result["key"], (str, type(None)))
+ if self.__valid_key.fullmatch(_soundness_check(result["key"], (str, type(None))))
else None
)apprise — apprise/plugins/apprise_api.py--- base/apprise/plugins/apprise_api.py
+++ head/apprise/plugins/apprise_api.py
@@ -568,22 +568,22 @@
schema=(
NotifyAppriseAPI.secure_protocol
- if result.group("secure")
+ if _soundness_check(result.group("secure"), str)
else NotifyAppriseAPI.protocol
),
- hostname=result.group("hostname"),
+ hostname=_soundness_check(result.group("hostname"), str),
port=(
""
- if not result.group("port")
- else ":{}".format(result.group("port"))
+ if not _soundness_check(result.group("port"), (str, type(None)))
+ else ":{}".format(_soundness_check(result.group("port"), (str, type(None))))
),
path=(
""
- if not result.group("path")
- else result.group("path")
... 401 characters elided ...
# "?" (it's captured by the regex), so it's used as-is.
- params=result.group("params") or "",
+ params=_soundness_check(result.group("params"), (str, type(None))) or "",
)
)apprise — apprise/plugins/bark.py--- base/apprise/plugins/bark.py
+++ head/apprise/plugins/bark.py
@@ -121,5 +121,5 @@
service_name: str = "Bark"
- requirements: dict[str, str] = {
+ requirements = {
"packages_recommended": "cryptography",
}apprise — apprise/plugins/base.py--- base/apprise/plugins/base.py
+++ head/apprise/plugins/base.py
@@ -535,13 +535,13 @@
_retry_raw,
)
- self.retry = min(
- max(0, self.asset.default_service_retry),
+ self.retry = _soundness_check(min(
+ _soundness_check(max(0, self.asset.default_service_retry), int),
APPRISE_MAX_SERVICE_RETRY,
- )
+ ), int)
else:
- self.retry = min(
- max(0, self.asset.default_service_retry),
+ self.retry = _soundness_check(min(
+ _soundness_check(max(0, self.asset.default_service_retry), int),
APPRISE_MAX_SERVICE_RETRY,
- )
+ ), int)
# Initialize wait (inter-retry delay) from (in priority order):apprise — apprise/plugins/blink1.py--- base/apprise/plugins/blink1.py
+++ head/apprise/plugins/blink1.py
@@ -148,5 +148,5 @@
enabled: bool = NOTIFY_BLINK1_ENABLED
- requirements: dict[str, str] = {
+ requirements = {
"packages_required": "hidapi",
}apprise — apprise/plugins/bluesky.py--- base/apprise/plugins/bluesky.py
+++ head/apprise/plugins/bluesky.py
@@ -164,6 +164,6 @@
results = HANDLE_HOST_PARSE_RE.match(self.user)
if results:
- self.user = results.group("handle").strip()
- self.host = results.group("host").strip()
+ self.user = _soundness_check(results.group("handle"), str).strip()
+ self.host = _soundness_check(results.group("host"), str).strip()
returnapprise — apprise/plugins/bulksms.py--- base/apprise/plugins/bulksms.py
+++ head/apprise/plugins/bulksms.py
@@ -249,5 +249,5 @@
# If the target specified is all digits, it MUST have a @
# in front of it to eliminate any ambiguity
- self.groups.append(group_re.group("group"))
+ self.groups.append(_soundness_check(group_re.group("group"), str))
continueapprise — apprise/plugins/fcm/__init__.py--- base/apprise/plugins/fcm/__init__.py
+++ head/apprise/plugins/fcm/__init__.py
@@ -97,5 +97,5 @@
enabled: bool = NOTIFY_FCM_SUPPORT_ENABLED
- requirements: dict[str, str] = {
+ requirements = {
# Define our required packaging in order to work
"packages_required": "cryptography"1206 finding(s) omitted to fit GitHub's 65536-character comment limit. Every finding, with nothing elided, is in the |
714 commits from astral-sh/ruff (sep 4 → oct 23 2026). the typeshed is
regenerated from upstream's `.pyi` rather than merged.
where the two sides now overlap, upstream's version is kept and the fork's
behaviour sits on top of it:
`redundant-condition` is upstream's lint now. the fork's declaration is gone,
and its conditions module keeps only `overlapping-condition` and the boolean
comparison checks. a truthiness test of `T | None` is reported by upstream's
`truthiness-test-of-none-union`, so `overlapping-condition` leaves `None` to it.
return types come from the fork's inference, gated by upstream's
`return-type-inference` option. the strict preset turns it on and the
ty-compatible preset keeps upstream's default. upstream's own body-inference
engine was unreachable behind the fork's and is deleted, and
`redundant-return-annotation` is gated on that option.
an ambiguous overload result stays the fork's `UnsafeUnion`.
requests on a closed file are answered from disk, as upstream now does. a
`textHash` is only needed when a client wants a specific text.
the return-type inlay hint setting takes upstream's name, `returnTypes`, in
place of the fork's `inferredReturnTypes`.
fixed along the way:
- a class or function returned from a body is generalized (`type[Point]`,
a callable) rather than handed back as that exact object; an instance of
a local class is returned as itself
- variance of a bound method no longer recurses forever, and neither does
`pep695_generic_context` for an enum variant
- `if let` clauses are not swept by the condition lints
- an implicit receiver imported from another module resolves again, even
after a later rebinding in the same scope
- a bare `case q:` that captures no longer exempts the rest of the scope from
`redundant-condition`
- `Overlapping[...]` is unwrapped before the lazy type variable step
- `type(name, bases, {})` infers the namespace against `dict[str, Any]`
- the inlay hint for a return type that never settles (`-> Divergent`) is gone
- django template tags are found beside a `.pyi` stub again
- the pygments lexer builds with `flit-core`, since build backends are now
pinned by hash
- a long `"a" | "b" | ...` type expression is walked in a loop rather than
recursively, which overflowed the test stack unoptimised (`dbm._TFlags`)
- the pep 695 typeshed conversion leaves a function legacy when it uses a
typevar imported from another module, so `max(xs, default=0)` and the keyed
`bisect` functions solve again
ci's scripts step is upstream's new one, over every PEP 723 script: the
upstream scripts it flagged are fixed, the fork's scripts are locked or pin
their build dependencies by hash, and the step fails on errors only, since the
fork makes every warning an error by default.
upstream now sets `required-version = ">=0.13.0"` for uv, so the fork's own
setup-uv steps (cargo test, zensical, the docs deploy and the ecosystem
round-trip) pin uv 0.13.5 as upstream's do.
upstream's zizmor config also forbids `taiki-e/install-action`, so the fork's
python-matrix test job takes nextest from the dev dependencies instead.
upstream's new attribute override check reports every drf serializer's
`class Meta:`, which replaces the stubs' `ModelSerializer.Meta` without
subclassing it (astral-sh/ty#4711). `external/drf.md` expects that error for
now, and a view whose `queryset` is another model's now reports where it is
assigned.
two of upstream's uv e2e tests are adjusted to the fork's server. after
corrected script metadata restores an environment, the rescan has already read
the installed package, so reporting it changes nothing and the server sends no
refresh. and the closed-script test waits for the synchronization to finish
rather than querying between refreshes, which could remember a module as
missing while uv was still installing it.
`ty_project` tests that assert a query did not run used a database that
recorded no events, so they passed whatever ran. `take_salsa_events` now
refuses a non-recording database.
e0b10f1 to
57db3e4
Compare
Merges
astral-sh/ruffthrough e330485: 714 upstream commits from Sep 4 to Oct 23 2026, as one merge commit. The vendored typeshed is regenerated from upstream's.pyirather than merged.Where the fork and upstream now overlap
redundant-condition: upstream's lint replaces the fork's. The fork keepsoverlapping-conditionand its boolean-comparison checks. A truthiness test ofT | Noneis upstream'struthiness-test-of-none-union.return-type-inferenceoption gates the fork's engine. The strict preset turns it on; ty-compatible keeps upstream's default. Upstream's own engine was unreachable behind the fork's and is deleted.redundant-return-annotationis gated on the option.UnsafeUnion.type[C], and an instance of one isC.textHashis only needed when a client names a specific text.inlayHints.returnTypes.Fixed along the way
pep695_generic_contexton an enum variant recursed forever.if letclauses were swept by the condition lints.case q:exempted the rest of its scope fromredundant-condition.type(name, bases, {})rejected{}, which predates the merge.-> Divergent..pyistub were not found.ty_projecttests that assert a query did not run passed vacuously; the test database now refuses to hand back events it never recorded."a" | "b" | ...type expression recursed once per member and overflowed the unoptimised test stack.TypeVarinto PEP 695 signatures, somax(xs, default=0)was rejected.CI changes
The scripts dogfood step is upstream's new one, which checks every PEP 723 script:
Upstream now requires uv 0.13 or later, so the fork's own setup-uv steps (cargo test, zensical, the docs deploy and the ecosystem round-trip) pin uv 0.13.5, as upstream's steps do.
Upstream's zizmor config also forbids
taiki-e/install-action, so the fork's Python-matrix test job installs nextest from the dev dependencies instead.The pygments lexer builds with
flit-core, since upstream now pins build backends by hash.Checked locally
cargo hawkwith no errors, and bothcargo docpasses with doc tests.cargo denyand all three dogfood steps.prek run --all-files.Known follow-ups (not in this PR)
class Meta:, which replaces the stubs'ModelSerializer.Metawithout subclassing it (astral-sh/ty#4711).external/drf.mdexpects the error for now.recursive_annotated_narrowing.py. CI does not check it at 3.7.NeverorNone, and its own body is never checked against it.classmethod[Owner, [int], str] = classmethod(make)is rejected.ty_python_semantic's crate version rather than basedpython's.sign-release-binariesnow gatesrelease.yml, so releases will not publish as merged.