Compare commits
141 Commits
thin-lto
...
zb/fmt-ski
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c8017ef13 | ||
|
|
d9845a2628 | ||
|
|
1f14d9a9f7 | ||
|
|
0202a49297 | ||
|
|
d0591561c9 | ||
|
|
2f5859e79e | ||
|
|
16085339bc | ||
|
|
074812115f | ||
|
|
9b17724d77 | ||
|
|
0d4af9d3c6 | ||
|
|
1dbfab9a0c | ||
|
|
501cca8b72 | ||
|
|
626b0577cd | ||
|
|
017e829115 | ||
|
|
2590aa30ae | ||
|
|
852a8f4a4f | ||
|
|
8365d2e0fd | ||
|
|
5b726f70f4 | ||
|
|
727e389cac | ||
|
|
0cb438dd65 | ||
|
|
63a87dda63 | ||
|
|
359a68d18f | ||
|
|
948094e691 | ||
|
|
f1ed0f27c2 | ||
|
|
5ce6299e22 | ||
|
|
5373759f62 | ||
|
|
d9151b1948 | ||
|
|
b61ce7fa46 | ||
|
|
6fb6478887 | ||
|
|
bf729e7a77 | ||
|
|
6ca2aaa245 | ||
|
|
e306359411 | ||
|
|
aec80dc3ab | ||
|
|
10d937c1a1 | ||
|
|
653e51ae97 | ||
|
|
04f0625d23 | ||
|
|
29dc8b986b | ||
|
|
f750257ef4 | ||
|
|
0f2c9ab4d2 | ||
|
|
779a5a9c32 | ||
|
|
bba43029d4 | ||
|
|
1de5425f7d | ||
|
|
71573fd35c | ||
|
|
95e2f632e6 | ||
|
|
00a015ca24 | ||
|
|
94178a0320 | ||
|
|
7165f8f05d | ||
|
|
415e808046 | ||
|
|
9279114521 | ||
|
|
8b86e8004d | ||
|
|
a7fc785cc5 | ||
|
|
f460f9c5c0 | ||
|
|
2faac1e7a8 | ||
|
|
b7dbb9062c | ||
|
|
66794bc9fe | ||
|
|
dca430f4d2 | ||
|
|
841e6c889e | ||
|
|
bd99175fea | ||
|
|
4c86b155f2 | ||
|
|
e2109c1353 | ||
|
|
1fcccf82fc | ||
|
|
14e65afdc6 | ||
|
|
6d5d079a18 | ||
|
|
d1e88dc984 | ||
|
|
dda31b6996 | ||
|
|
b6a7787318 | ||
|
|
5fa961f670 | ||
|
|
2424188bb2 | ||
|
|
a59172528c | ||
|
|
cd29761b9c | ||
|
|
4ac78d5725 | ||
|
|
2083352ae3 | ||
|
|
0e2ece5217 | ||
|
|
a783b14e7d | ||
|
|
9d76e4e0b9 | ||
|
|
561277925f | ||
|
|
1074324c52 | ||
|
|
4099b9610f | ||
|
|
f7d249ae06 | ||
|
|
bf2cc3f520 | ||
|
|
23c819b4b3 | ||
|
|
16060670b8 | ||
|
|
534fc34f11 | ||
|
|
df9ade7fd9 | ||
|
|
345e1401cf | ||
|
|
a8e0d4ab4f | ||
|
|
6f23bdb78f | ||
|
|
d574fcd1ac | ||
|
|
3592f44ade | ||
|
|
8984072df2 | ||
|
|
6a6de53722 | ||
|
|
5ba852a878 | ||
|
|
c4fc2b8584 | ||
|
|
1c5f2288ba | ||
|
|
62f1830898 | ||
|
|
abca0a86ea | ||
|
|
213d315373 | ||
|
|
7fd95e15d9 | ||
|
|
02946e7b0c | ||
|
|
cbd9157bbf | ||
|
|
70f491d31e | ||
|
|
776eb8724f | ||
|
|
5f78580775 | ||
|
|
4d301f6dcc | ||
|
|
96b265ccec | ||
|
|
e0a0ddcf7d | ||
|
|
9724dfd939 | ||
|
|
d7144d6d8e | ||
|
|
39728a1198 | ||
|
|
8207d6df82 | ||
|
|
c8edac9d2b | ||
|
|
5a1a8bebca | ||
|
|
3e00ddce38 | ||
|
|
a7dbe9d670 | ||
|
|
036b6bc0bd | ||
|
|
d5606b7705 | ||
|
|
7968e190dd | ||
|
|
346a828db2 | ||
|
|
0ac124acef | ||
|
|
4ebd0bd31e | ||
|
|
565ddebb15 | ||
|
|
9d167a1f5c | ||
|
|
9e184a9067 | ||
|
|
9d1027c239 | ||
|
|
f499f0ca60 | ||
|
|
722687ad72 | ||
|
|
4760af3dcb | ||
|
|
4fdf97a95c | ||
|
|
0ea1076f85 | ||
|
|
3956f38999 | ||
|
|
fe9727ac38 | ||
|
|
3ebaca5246 | ||
|
|
7391f74cbc | ||
|
|
71e93a9fa4 | ||
|
|
e2c7b1ece6 | ||
|
|
621e98f452 | ||
|
|
0126f74c29 | ||
|
|
fce9f63418 | ||
|
|
ce549e75bc | ||
|
|
03303a9edd | ||
|
|
7873ca38e5 |
@@ -1,37 +1,3 @@
|
||||
[alias]
|
||||
dev = "run --package ruff_dev --bin ruff_dev"
|
||||
benchmark = "bench -p ruff_benchmark --bench linter --bench formatter --"
|
||||
|
||||
[target.'cfg(all())']
|
||||
rustflags = [
|
||||
# CLIPPY LINT SETTINGS
|
||||
# This is a workaround to configure lints for the entire workspace, pending the ability to configure this via TOML.
|
||||
# See: `https://github.com/rust-lang/cargo/issues/5034`
|
||||
# `https://github.com/EmbarkStudios/rust-ecosystem/issues/22#issuecomment-947011395`
|
||||
"-Dunsafe_code",
|
||||
"-Wclippy::pedantic",
|
||||
# Allowed pedantic lints
|
||||
"-Wclippy::char_lit_as_u8",
|
||||
"-Aclippy::collapsible_else_if",
|
||||
"-Aclippy::collapsible_if",
|
||||
"-Aclippy::implicit_hasher",
|
||||
"-Aclippy::match_same_arms",
|
||||
"-Aclippy::missing_errors_doc",
|
||||
"-Aclippy::missing_panics_doc",
|
||||
"-Aclippy::module_name_repetitions",
|
||||
"-Aclippy::must_use_candidate",
|
||||
"-Aclippy::similar_names",
|
||||
"-Aclippy::too_many_lines",
|
||||
# Disallowed restriction lints
|
||||
"-Wclippy::print_stdout",
|
||||
"-Wclippy::print_stderr",
|
||||
"-Wclippy::dbg_macro",
|
||||
"-Wclippy::empty_drop",
|
||||
"-Wclippy::empty_structs_with_brackets",
|
||||
"-Wclippy::exit",
|
||||
"-Wclippy::get_unwrap",
|
||||
"-Wclippy::rc_buffer",
|
||||
"-Wclippy::rc_mutex",
|
||||
"-Wclippy::rest_pat_in_fully_bound_structs",
|
||||
"-Wunreachable_pub"
|
||||
]
|
||||
|
||||
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -3,5 +3,8 @@
|
||||
crates/ruff_linter/resources/test/fixtures/isort/line_ending_crlf.py text eol=crlf
|
||||
crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_1.py text eol=crlf
|
||||
|
||||
crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.py text eol=crlf
|
||||
crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap text eol=crlf
|
||||
|
||||
ruff.schema.json linguist-generated=true text=auto eol=lf
|
||||
*.md.snap linguist-language=Markdown
|
||||
|
||||
29
.github/release.yml
vendored
29
.github/release.yml
vendored
@@ -1,29 +0,0 @@
|
||||
# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes
|
||||
changelog:
|
||||
exclude:
|
||||
labels:
|
||||
- internal
|
||||
- documentation
|
||||
categories:
|
||||
- title: Breaking Changes
|
||||
labels:
|
||||
- breaking
|
||||
- title: Rules
|
||||
labels:
|
||||
- rule
|
||||
- title: Settings
|
||||
labels:
|
||||
- configuration
|
||||
- cli
|
||||
- title: Bug Fixes
|
||||
labels:
|
||||
- bug
|
||||
- title: Formatter
|
||||
labels:
|
||||
- formatter
|
||||
- title: Preview
|
||||
labels:
|
||||
- preview
|
||||
- title: Other Changes
|
||||
labels:
|
||||
- "*"
|
||||
4
.github/workflows/ci.yaml
vendored
4
.github/workflows/ci.yaml
vendored
@@ -44,6 +44,7 @@ jobs:
|
||||
- "!crates/ruff_shrinking/**"
|
||||
- scripts/*
|
||||
- .github/workflows/ci.yaml
|
||||
- python/**
|
||||
|
||||
formatter:
|
||||
- Cargo.toml
|
||||
@@ -58,6 +59,7 @@ jobs:
|
||||
- crates/ruff_python_parser/**
|
||||
- crates/ruff_dev/**
|
||||
- scripts/*
|
||||
- python/**
|
||||
- .github/workflows/ci.yaml
|
||||
|
||||
cargo-fmt:
|
||||
@@ -392,7 +394,7 @@ jobs:
|
||||
run: mkdocs build --strict -f mkdocs.insiders.yml
|
||||
- name: "Build docs"
|
||||
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS != 'true' }}
|
||||
run: mkdocs build --strict -f mkdocs.generated.yml
|
||||
run: mkdocs build --strict -f mkdocs.public.yml
|
||||
|
||||
check-formatter-instability-and-black-similarity:
|
||||
name: "formatter instabilities and black similarity"
|
||||
|
||||
2
.github/workflows/docs.yaml
vendored
2
.github/workflows/docs.yaml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
run: mkdocs build --strict -f mkdocs.insiders.yml
|
||||
- name: "Build docs"
|
||||
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS != 'true' }}
|
||||
run: mkdocs build --strict -f mkdocs.generated.yml
|
||||
run: mkdocs build --strict -f mkdocs.public.yml
|
||||
- name: "Deploy to Cloudflare Pages"
|
||||
if: ${{ env.CF_API_TOKEN_EXISTS == 'true' }}
|
||||
uses: cloudflare/wrangler-action@v3.3.2
|
||||
|
||||
58
.github/workflows/release.yaml
vendored
58
.github/workflows/release.yaml
vendored
@@ -516,6 +516,62 @@ jobs:
|
||||
files: binaries/*
|
||||
tag_name: v${{ inputs.tag }}
|
||||
|
||||
docker-publish:
|
||||
# This action doesn't need to wait on any other task, it's easy to re-tag if something failed and we're validating
|
||||
# the tag here also
|
||||
name: Push Docker image ghcr.io/astral-sh/ruff
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: release
|
||||
permissions:
|
||||
# For the docker push
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.sha }}
|
||||
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/astral-sh/ruff
|
||||
|
||||
- name: Check tag consistency
|
||||
# Unlike validate-tag we don't check if the commit is on the main branch, but it seems good enough since we can
|
||||
# change docker tags
|
||||
if: ${{ inputs.tag }}
|
||||
run: |
|
||||
version=$(grep "version = " pyproject.toml | sed -e 's/version = "\(.*\)"/\1/g')
|
||||
if [ "${{ inputs.tag }}" != "${version}" ]; then
|
||||
echo "The input tag does not match the version from pyproject.toml:" >&2
|
||||
echo "${{ inputs.tag }}" >&2
|
||||
echo "${version}" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "Releasing ${version}"
|
||||
fi
|
||||
|
||||
- name: "Build and push Docker image"
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
# Reuse the builder
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
push: ${{ inputs.tag != '' }}
|
||||
tags: ghcr.io/astral-sh/ruff:latest,ghcr.io/astral-sh/ruff:${{ inputs.tag || 'dry-run' }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
# After the release has been published, we update downstream repositories
|
||||
# This is separate because if this fails the release is still fine, we just need to do some manual workflow triggers
|
||||
update-dependents:
|
||||
@@ -524,7 +580,7 @@ jobs:
|
||||
needs: publish-release
|
||||
steps:
|
||||
- name: "Update pre-commit mirror"
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.RUFF_PRE_COMMIT_PAT }}
|
||||
script: |
|
||||
|
||||
122
CHANGELOG.md
122
CHANGELOG.md
@@ -1,5 +1,127 @@
|
||||
# Changelog
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Preview features
|
||||
|
||||
- \[`flake8-boolean-trap`\] Extend `boolean-type-hint-positional-argument` (`FBT001`) to include booleans in unions ([#7501](https://github.com/astral-sh/ruff/pull/7501))
|
||||
- \[`flake8-pie`\] Extend `reimplemented-list-builtin` (`PIE807`) to `dict` reimplementations ([#8608](https://github.com/astral-sh/ruff/pull/8608))
|
||||
- \[`flake8-pie`\] Extend `unnecessary-pass` (`PIE790`) to include ellipses (`...`) ([#8641](https://github.com/astral-sh/ruff/pull/8641))
|
||||
- \[`flake8-pie`\] Implement fix for `unnecessary-spread` (`PIE800`) ([#8668](https://github.com/astral-sh/ruff/pull/8668))
|
||||
- \[`flake8-quotes`\] Implement `unnecessary-escaped-quote` (`Q004`) ([#8630](https://github.com/astral-sh/ruff/pull/8630))
|
||||
- \[`pycodestyle`\] Implement fix for `multiple-spaces-after-keyword` (`E271`) and `multiple-spaces-before-keyword` (`E272`) ([#8622](https://github.com/astral-sh/ruff/pull/8622))
|
||||
- \[`pycodestyle`\] Implement fix for `multiple-spaces-after-operator` (`E222`) and `multiple-spaces-before-operator` (`E221`) ([#8623](https://github.com/astral-sh/ruff/pull/8623))
|
||||
- \[`pyflakes`\] Extend `is-literal` (`F632`) to include comparisons against mutable initializers ([#8607](https://github.com/astral-sh/ruff/pull/8607))
|
||||
- \[`pylint`\] Implement `redefined-argument-from-local` (`PLR1704`) ([#8159](https://github.com/astral-sh/ruff/pull/8159))
|
||||
- \[`pylint`\] Implement fix for `unnecessary-lambda` (`PLW0108`) ([#8621](https://github.com/astral-sh/ruff/pull/8621))
|
||||
- \[`refurb`\] Implement `if-expr-min-max` (`FURB136`) ([#8664](https://github.com/astral-sh/ruff/pull/8664))
|
||||
- \[`refurb`\] Implement `math-constant` (`FURB152`) ([#8727](https://github.com/astral-sh/ruff/pull/8727))
|
||||
|
||||
### Rule changes
|
||||
|
||||
- \[`flake8-annotations`\] Add autotyping-like return type inference for annotation rules ([#8643](https://github.com/astral-sh/ruff/pull/8643))
|
||||
- \[`flake8-future-annotations`\] Implement fix for `future-required-type-annotation` (`FA102`) ([#8711](https://github.com/astral-sh/ruff/pull/8711))
|
||||
- \[`flake8-implicit-namespace-package`\] Avoid missing namespace violations in scripts with shebangs ([#8710](https://github.com/astral-sh/ruff/pull/8710))
|
||||
- \[`pydocstyle`\] Update `over-indentation` (`D208`) to preserve indentation offsets when fixing overindented lines ([#8699](https://github.com/astral-sh/ruff/pull/8699))
|
||||
- \[`pyupgrade`\] Refine `timeout-error-alias` (`UP041`) to remove false positives ([#8587](https://github.com/astral-sh/ruff/pull/8587))
|
||||
|
||||
### Formatter
|
||||
|
||||
- Fix instability in `await` formatting with fluent style ([#8676](https://github.com/astral-sh/ruff/pull/8676))
|
||||
- Compare formatted and unformatted ASTs during formatter tests ([#8624](https://github.com/astral-sh/ruff/pull/8624))
|
||||
- Preserve trailing semicolon for Notebooks ([#8590](https://github.com/astral-sh/ruff/pull/8590))
|
||||
|
||||
### CLI
|
||||
|
||||
- Improve debug printing for resolving origin of config settings ([#8729](https://github.com/astral-sh/ruff/pull/8729))
|
||||
- Write unchanged, excluded files to stdout when read via stdin ([#8596](https://github.com/astral-sh/ruff/pull/8596))
|
||||
|
||||
### Configuration
|
||||
|
||||
- \[`isort`\] Support disabling sections with `no-sections = true` ([#8657](https://github.com/astral-sh/ruff/pull/8657))
|
||||
- \[`pep8-naming`\] Support local and dynamic class- and static-method decorators ([#8592](https://github.com/astral-sh/ruff/pull/8592))
|
||||
- \[`pydocstyle`\] Allow overriding pydocstyle convention rules ([#8586](https://github.com/astral-sh/ruff/pull/8586))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Avoid syntax error via importing `trio.lowlevel` ([#8730](https://github.com/astral-sh/ruff/pull/8730))
|
||||
- Omit unrolled augmented assignments in `PIE794` ([#8634](https://github.com/astral-sh/ruff/pull/8634))
|
||||
- Slice source code instead of generating it for `EM` fixes ([#7746](https://github.com/astral-sh/ruff/pull/7746))
|
||||
- Allow whitespace around colon in slices for `whitespace-before-punctuation` (`E203`) ([#8654](https://github.com/astral-sh/ruff/pull/8654))
|
||||
- Use function range for `no-self-use` ([#8637](https://github.com/astral-sh/ruff/pull/8637))
|
||||
- F-strings doesn't contain bytes literal for `PLW0129` ([#8675](https://github.com/astral-sh/ruff/pull/8675))
|
||||
- Improve detection of `TYPE_CHECKING` blocks imported from `typing_extensions` or `_typeshed` ([#8429](https://github.com/astral-sh/ruff/pull/8429))
|
||||
- Treat display as a builtin in IPython ([#8707](https://github.com/astral-sh/ruff/pull/8707))
|
||||
- Avoid `FURB113` autofix if comments are present ([#8494](https://github.com/astral-sh/ruff/pull/8494))
|
||||
- Consider the new f-string tokens for `flake8-commas` ([#8582](https://github.com/astral-sh/ruff/pull/8582))
|
||||
- Remove erroneous bad-dunder-name reference ([#8742](https://github.com/astral-sh/ruff/pull/8742))
|
||||
- Avoid recommending Self usages in metaclasses ([#8639](https://github.com/astral-sh/ruff/pull/8639))
|
||||
- Detect runtime-evaluated base classes defined in the current file ([#8572](https://github.com/astral-sh/ruff/pull/8572))
|
||||
- Avoid inserting trailing commas within f-strings ([#8574](https://github.com/astral-sh/ruff/pull/8574))
|
||||
- Remove incorrect deprecation label for stdout and stderr ([#8743](https://github.com/astral-sh/ruff/pull/8743))
|
||||
- Fix unnecessary parentheses in UP007 fix ([#8610](https://github.com/astral-sh/ruff/pull/8610))
|
||||
- Remove repeated and erroneous scoped settings headers in docs ([#8670](https://github.com/astral-sh/ruff/pull/8670))
|
||||
- Trim trailing empty strings when converting to f-strings ([#8712](https://github.com/astral-sh/ruff/pull/8712))
|
||||
- Fix ordering for `force-sort-within-sections` ([#8665](https://github.com/astral-sh/ruff/pull/8665))
|
||||
- Run unicode prefix rule over tokens ([#8709](https://github.com/astral-sh/ruff/pull/8709))
|
||||
- Update UP032 to unescape curly braces in literal parts of converted strings ([#8697](https://github.com/astral-sh/ruff/pull/8697))
|
||||
- List all ipython builtins ([#8719](https://github.com/astral-sh/ruff/pull/8719))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Document conventions in the FAQ ([#8638](https://github.com/astral-sh/ruff/pull/8638))
|
||||
- Redirect from rule codes to rule pages in docs ([#8636](https://github.com/astral-sh/ruff/pull/8636))
|
||||
- Fix permalink to convention setting ([#8575](https://github.com/astral-sh/ruff/pull/8575))
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Preview features
|
||||
|
||||
- \[`flake8-bandit`\] Implement `mako-templates` (`S702`) ([#8533](https://github.com/astral-sh/ruff/pull/8533))
|
||||
- \[`flake8-trio`\] Implement `TRIO105` ([#8490](https://github.com/astral-sh/ruff/pull/8490))
|
||||
- \[`flake8-trio`\] Implement `TRIO109` ([#8534](https://github.com/astral-sh/ruff/pull/8534))
|
||||
- \[`flake8-trio`\] Implement `TRIO110` ([#8537](https://github.com/astral-sh/ruff/pull/8537))
|
||||
- \[`flake8-trio`\] Implement `TRIO115` ([#8486](https://github.com/astral-sh/ruff/pull/8486))
|
||||
- \[`refurb`\] Implement `type-none-comparison` (`FURB169`) ([#8487](https://github.com/astral-sh/ruff/pull/8487))
|
||||
- Flag all comparisons against builtin types in `E721` ([#8491](https://github.com/astral-sh/ruff/pull/8491))
|
||||
- Make `SIM118` fix as safe when the expression is a known dictionary ([#8525](https://github.com/astral-sh/ruff/pull/8525))
|
||||
|
||||
### Formatter
|
||||
|
||||
- Fix multiline lambda expression statement formatting ([#8466](https://github.com/astral-sh/ruff/pull/8466))
|
||||
|
||||
### CLI
|
||||
|
||||
- Add hidden `--extension` to override inference of source type from file extension ([#8373](https://github.com/astral-sh/ruff/pull/8373))
|
||||
|
||||
### Configuration
|
||||
|
||||
- Account for selector specificity when merging `extend_unsafe_fixes` and `override extend_safe_fixes` ([#8444](https://github.com/astral-sh/ruff/pull/8444))
|
||||
- Add support for disabling cache with `RUFF_NO_CACHE` environment variable ([#8538](https://github.com/astral-sh/ruff/pull/8538))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- \[`E721`\] Flag comparisons to `memoryview` ([#8485](https://github.com/astral-sh/ruff/pull/8485))
|
||||
- Allow collapsed-ellipsis bodies in other statements ([#8499](https://github.com/astral-sh/ruff/pull/8499))
|
||||
- Avoid `D301` autofix for `u` prefixed strings ([#8495](https://github.com/astral-sh/ruff/pull/8495))
|
||||
- Only flag `flake8-trio` rules when `trio` import is present ([#8550](https://github.com/astral-sh/ruff/pull/8550))
|
||||
- Reject more syntactically invalid Python programs ([#8524](https://github.com/astral-sh/ruff/pull/8524))
|
||||
- Avoid raising `TRIO115` violations for `trio.sleep(...)` calls with non-number values ([#8532](https://github.com/astral-sh/ruff/pull/8532))
|
||||
- Fix `F841` false negative on assignment to multiple variables ([#8489](https://github.com/astral-sh/ruff/pull/8489))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Fix link to isort `known-first-party` ([#8562](https://github.com/astral-sh/ruff/pull/8562))
|
||||
- Add notes on fix safety to a few rules ([#8500](https://github.com/astral-sh/ruff/pull/8500))
|
||||
- Add missing toml config tabs ([#8512](https://github.com/astral-sh/ruff/pull/8512))
|
||||
- Add instructions for configuration of Emacs ([#8488](https://github.com/astral-sh/ruff/pull/8488))
|
||||
- Improve detail link contrast in dark mode ([#8548](https://github.com/astral-sh/ruff/pull/8548))
|
||||
- Fix typo in example ([#8506](https://github.com/astral-sh/ruff/pull/8506))
|
||||
- Added tabs for configuration files in the documentation ([#8480](https://github.com/astral-sh/ruff/pull/8480))
|
||||
- Recommend `project.requires-python` over `target-version` ([#8513](https://github.com/astral-sh/ruff/pull/8513))
|
||||
- Add singleton escape hatch to `B008` documentation ([#8501](https://github.com/astral-sh/ruff/pull/8501))
|
||||
- Fix tab configuration docs ([#8502](https://github.com/astral-sh/ruff/pull/8502))
|
||||
|
||||
## 0.1.4
|
||||
|
||||
### Preview features
|
||||
|
||||
@@ -295,7 +295,7 @@ To preview any changes to the documentation locally:
|
||||
|
||||
```shell
|
||||
# For contributors.
|
||||
mkdocs serve -f mkdocs.generated.yml
|
||||
mkdocs serve -f mkdocs.public.yml
|
||||
|
||||
# For members of the Astral org, which has access to MkDocs Insiders via sponsorship.
|
||||
mkdocs serve -f mkdocs.insiders.yml
|
||||
@@ -315,9 +315,18 @@ even patch releases may contain [non-backwards-compatible changes](https://semve
|
||||
|
||||
### Creating a new release
|
||||
|
||||
1. Update the version with `rg 0.0.269 --files-with-matches | xargs sed -i 's/0.0.269/0.0.270/g'`
|
||||
1. Update `BREAKING_CHANGES.md`
|
||||
1. Create a PR with the version and `BREAKING_CHANGES.md` updated
|
||||
We use an experimental in-house tool for managing releases.
|
||||
|
||||
1. Install `rooster`: `pip install git+https://github.com/zanieb/rooster@main`
|
||||
1. Run `rooster release`; this command will:
|
||||
- Generate a changelog entry in `CHANGELOG.md`
|
||||
- Update versions in `pyproject.toml` and `Cargo.toml`
|
||||
- Update references to versions in the `README.md` and documentation
|
||||
1. The changelog should then be editorialized for consistency
|
||||
- Often labels will be missing from pull requests they will need to be manually organized into the proper section
|
||||
- Changes should be edited to be user-facing descriptions, avoiding internal details
|
||||
1. Highlight any breaking changes in `BREAKING_CHANGES.md`
|
||||
1. Create a pull request with the changelog and version updates
|
||||
1. Merge the PR
|
||||
1. Run the release workflow with the version number (without starting `v`) as input. Make sure
|
||||
main has your merged PR as last commit
|
||||
@@ -330,7 +339,11 @@ even patch releases may contain [non-backwards-compatible changes](https://semve
|
||||
1. Attach artifacts to draft GitHub release
|
||||
1. Trigger downstream repositories. This can fail non-catastrophically, as we can run any
|
||||
downstream jobs manually if needed.
|
||||
1. Create release notes in GitHub UI and promote from draft.
|
||||
1. Publish the GitHub release
|
||||
1. Open the draft release in the GitHub release section
|
||||
1. Copy the changelog for the release into the GitHub release
|
||||
- See previous releases for formatting of section headers
|
||||
1. Generate the contributor list with `rooster contributors` and add to the release notes
|
||||
1. If needed, [update the schemastore](https://github.com/charliermarsh/ruff/blob/main/scripts/update_schemastore.py)
|
||||
1. If needed, update the `ruff-lsp` and `ruff-vscode` repositories.
|
||||
|
||||
|
||||
178
Cargo.lock
generated
178
Cargo.lock
generated
@@ -64,9 +64,9 @@ checksum = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7"
|
||||
|
||||
[[package]]
|
||||
name = "annotate-snippets"
|
||||
version = "0.9.1"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3b9d411ecbaf79885c6df4d75fff75858d5995ff25385657a28af47e82f9c36"
|
||||
checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
"yansi-term",
|
||||
@@ -278,9 +278,7 @@ checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
@@ -407,9 +405,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "codspeed"
|
||||
version = "2.3.1"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "918b13a0f1a32460ab3bd5debd56b5a27a7071fa5ff5dfeb3a5cf291a85b174b"
|
||||
checksum = "0eb4ab4dcb6554eb4f590fb16f99d3b102ab76f5f56554c9a5340518b32c499b"
|
||||
dependencies = [
|
||||
"colored",
|
||||
"libc",
|
||||
@@ -418,9 +416,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "codspeed-criterion-compat"
|
||||
version = "2.3.1"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c683c7fef2b873fbbdf4062782914c652309951244bf0bd362fe608b7d6f901c"
|
||||
checksum = "cc07a3d3f7e0c8961d0ffdee149d39b231bafdcdc3d978dc5ad790c615f55f3f"
|
||||
dependencies = [
|
||||
"codspeed",
|
||||
"colored",
|
||||
@@ -446,9 +444,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "configparser"
|
||||
version = "3.0.2"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5458d9d1a587efaf5091602c59d299696a3877a439c8f6d461a2d3cce11df87a"
|
||||
checksum = "e0e56e414a2a52ab2a104f85cd40933c2fbc278b83637facf646ecf451b49237"
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
@@ -810,7 +808,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -829,7 +827,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"toml",
|
||||
"toml 0.7.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -859,9 +857,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fs-err"
|
||||
version = "2.9.0"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541"
|
||||
checksum = "fb5fd9bcbe8b1087cbd395b51498c01bc997cef73e778a80b77a811af5e2d29f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
@@ -902,15 +903,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.13"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d"
|
||||
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"fnv",
|
||||
"log",
|
||||
"regex",
|
||||
"regex-automata 0.4.3",
|
||||
"regex-syntax 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -927,9 +928,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -1033,12 +1034,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.0",
|
||||
"hashbrown 0.14.2",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -1169,9 +1170,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.64"
|
||||
version = "0.3.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
|
||||
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@@ -1792,45 +1793,46 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyproject-toml"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0774c13ff0b8b7ebb4791c050c497aefcfe3f6a222c0829c7017161ed38391ff"
|
||||
checksum = "46d4a5e69187f23a29f8aa0ea57491d104ba541bc55f76552c2a74962aa20e04"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"pep440_rs",
|
||||
"pep508_rs",
|
||||
"serde",
|
||||
"toml",
|
||||
"toml 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-junit"
|
||||
version = "0.3.3"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bf780b59d590c25f8c59b44c124166a2a93587868b619fb8f5b47fb15e9ed6d"
|
||||
checksum = "1b9599bffc2cd7511355996e0cfd979266b2cfa3f3ff5247d07a3a6e1ded6158"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"indexmap",
|
||||
"nextest-workspace-hack",
|
||||
"quick-xml",
|
||||
"strip-ansi-escapes",
|
||||
"thiserror",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.29.0"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51"
|
||||
checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -2060,9 +2062,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"annotate-snippets 0.9.2",
|
||||
"anyhow",
|
||||
"argfile",
|
||||
"assert_cmd",
|
||||
@@ -2152,7 +2154,7 @@ dependencies = [
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tempfile",
|
||||
"toml",
|
||||
"toml 0.7.8",
|
||||
"tracing",
|
||||
"tracing-indicatif",
|
||||
"tracing-subscriber",
|
||||
@@ -2196,10 +2198,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_linter"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"annotate-snippets 0.9.1",
|
||||
"annotate-snippets 0.9.2",
|
||||
"anyhow",
|
||||
"bitflags 2.4.1",
|
||||
"chrono",
|
||||
@@ -2252,7 +2254,7 @@ dependencies = [
|
||||
"tempfile",
|
||||
"test-case",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"toml 0.7.8",
|
||||
"typed-arena",
|
||||
"unicode-width",
|
||||
"unicode_names2",
|
||||
@@ -2332,6 +2334,7 @@ dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"ruff_cache",
|
||||
"ruff_formatter",
|
||||
"ruff_macros",
|
||||
@@ -2447,7 +2450,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_shrinking"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -2538,7 +2541,7 @@ dependencies = [
|
||||
"shellexpand",
|
||||
"strum",
|
||||
"tempfile",
|
||||
"toml",
|
||||
"toml 0.7.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2802,9 +2805,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.1"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
@@ -2831,6 +2834,15 @@ dependencies = [
|
||||
"precomputed-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strip-ansi-escapes"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa"
|
||||
dependencies = [
|
||||
"vte",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
@@ -3086,7 +3098,19 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
"toml_edit 0.19.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit 0.20.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3111,6 +3135,19 @@ dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.40"
|
||||
@@ -3158,20 +3195,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.3"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
|
||||
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
@@ -3331,9 +3368,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.5.0"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||
checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"rand",
|
||||
@@ -3343,9 +3380,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uuid-macro-internal"
|
||||
version = "1.5.0"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d8c6bba9b149ee82950daefc9623b32bb1dacbfb1890e352f6b887bd582adaf"
|
||||
checksum = "f49e7f3f3db8040a100710a11932239fd30697115e2ba4107080d8252939845e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3424,9 +3461,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.87"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
|
||||
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
@@ -3434,9 +3471,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.87"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
|
||||
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
@@ -3449,9 +3486,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.37"
|
||||
version = "0.4.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
|
||||
checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -3461,9 +3498,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.87"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
|
||||
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -3471,9 +3508,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.87"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
||||
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3484,15 +3521,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.87"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
|
||||
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test"
|
||||
version = "0.3.37"
|
||||
version = "0.3.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671"
|
||||
checksum = "c6433b7c56db97397842c46b67e11873eda263170afeb3a2dc74a7cb370fee0d"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
@@ -3504,12 +3541,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test-macro"
|
||||
version = "0.3.37"
|
||||
version = "0.3.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575"
|
||||
checksum = "493fcbab756bb764fa37e6bee8cec2dd709eb4273d06d0c282a5e74275ded735"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
44
Cargo.toml
44
Cargo.toml
@@ -19,7 +19,7 @@ clap = { version = "4.4.7", features = ["derive"] }
|
||||
colored = { version = "2.0.0" }
|
||||
filetime = { version = "0.2.20" }
|
||||
glob = { version = "0.3.1" }
|
||||
globset = { version = "0.4.10" }
|
||||
globset = { version = "0.4.14" }
|
||||
ignore = { version = "0.4.20" }
|
||||
insta = { version = "1.34.0", feature = ["filters", "glob"] }
|
||||
is-macro = { version = "0.3.0" }
|
||||
@@ -29,7 +29,7 @@ log = { version = "0.4.17" }
|
||||
memchr = { version = "2.6.4" }
|
||||
once_cell = { version = "1.17.1" }
|
||||
path-absolutize = { version = "3.1.1" }
|
||||
proc-macro2 = { version = "1.0.69" }
|
||||
proc-macro2 = { version = "1.0.70" }
|
||||
quote = { version = "1.0.23" }
|
||||
regex = { version = "1.10.2" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
@@ -38,7 +38,7 @@ serde = { version = "1.0.190", features = ["derive"] }
|
||||
serde_json = { version = "1.0.108" }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
similar = { version = "2.3.0", features = ["inline"] }
|
||||
smallvec = { version = "1.11.1" }
|
||||
smallvec = { version = "1.11.2" }
|
||||
static_assertions = "1.1.0"
|
||||
strum = { version = "0.25.0", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.25.3" }
|
||||
@@ -48,15 +48,47 @@ thiserror = { version = "1.0.50" }
|
||||
toml = { version = "0.7.8" }
|
||||
tracing = { version = "0.1.40" }
|
||||
tracing-indicatif = { version = "0.3.4" }
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
unicode-ident = { version = "1.0.12" }
|
||||
unicode_names2 = { version = "1.2.0" }
|
||||
unicode-width = { version = "0.1.11" }
|
||||
uuid = { version = "1.5.0", features = ["v4", "fast-rng", "macro-diagnostics", "js"] }
|
||||
uuid = { version = "1.6.1", features = ["v4", "fast-rng", "macro-diagnostics", "js"] }
|
||||
wsl = { version = "0.1.0" }
|
||||
|
||||
[workspace.lints.rust]
|
||||
unsafe_code = "warn"
|
||||
unreachable_pub = "warn"
|
||||
|
||||
[workspace.lints.clippy]
|
||||
pedantic = { level = "warn", priority = -2 }
|
||||
# Allowed pedantic lints
|
||||
char_lit_as_u8 = "allow"
|
||||
collapsible_else_if = "allow"
|
||||
collapsible_if = "allow"
|
||||
implicit_hasher = "allow"
|
||||
match_same_arms = "allow"
|
||||
missing_errors_doc = "allow"
|
||||
missing_panics_doc = "allow"
|
||||
module_name_repetitions = "allow"
|
||||
must_use_candidate = "allow"
|
||||
similar_names = "allow"
|
||||
too_many_lines = "allow"
|
||||
# To allow `#[allow(clippy::all)]` in `crates/ruff_python_parser/src/python.rs`.
|
||||
needless_raw_string_hashes = "allow"
|
||||
# Disallowed restriction lints
|
||||
print_stdout = "warn"
|
||||
print_stderr = "warn"
|
||||
dbg_macro = "warn"
|
||||
empty_drop = "warn"
|
||||
empty_structs_with_brackets = "warn"
|
||||
exit = "warn"
|
||||
get_unwrap = "warn"
|
||||
rc_buffer = "warn"
|
||||
rc_mutex = "warn"
|
||||
rest_pat_in_fully_bound_structs = "warn"
|
||||
|
||||
[profile.release]
|
||||
lto = "thin"
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
|
||||
[profile.dev.package.insta]
|
||||
|
||||
38
Dockerfile
Normal file
38
Dockerfile
Normal file
@@ -0,0 +1,38 @@
|
||||
FROM --platform=$BUILDPLATFORM ubuntu as build
|
||||
ENV HOME="/root"
|
||||
WORKDIR $HOME
|
||||
|
||||
RUN apt update && apt install -y build-essential curl python3-venv
|
||||
|
||||
# Setup zig as cross compiling linker
|
||||
RUN python3 -m venv $HOME/.venv
|
||||
RUN .venv/bin/pip install cargo-zigbuild
|
||||
ENV PATH="$HOME/.venv/bin:$PATH"
|
||||
|
||||
# Install rust
|
||||
ARG TARGETPLATFORM
|
||||
RUN case "$TARGETPLATFORM" in \
|
||||
"linux/arm64") echo "aarch64-unknown-linux-musl" > rust_target.txt ;; \
|
||||
"linux/amd64") echo "x86_64-unknown-linux-musl" > rust_target.txt ;; \
|
||||
*) exit 1 ;; \
|
||||
esac
|
||||
# Update rustup whenever we bump the rust version
|
||||
COPY rust-toolchain.toml rust-toolchain.toml
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --target $(cat rust_target.txt) --profile minimal --default-toolchain none
|
||||
ENV PATH="$HOME/.cargo/bin:$PATH"
|
||||
# Installs the correct toolchain version from rust-toolchain.toml and then the musl target
|
||||
RUN rustup target add $(cat rust_target.txt)
|
||||
|
||||
# Build
|
||||
COPY crates crates
|
||||
COPY Cargo.toml Cargo.toml
|
||||
COPY Cargo.lock Cargo.lock
|
||||
RUN cargo zigbuild --bin ruff --target $(cat rust_target.txt) --release
|
||||
RUN cp target/$(cat rust_target.txt)/release/ruff /ruff
|
||||
# TODO: Optimize binary size, with a version that also works when cross compiling
|
||||
# RUN strip --strip-all /ruff
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build /ruff /ruff
|
||||
WORKDIR /io
|
||||
ENTRYPOINT ["/ruff"]
|
||||
25
README.md
25
README.md
@@ -54,7 +54,7 @@ Ruff is extremely actively developed and used in major open-source projects like
|
||||
- [Pandas](https://github.com/pandas-dev/pandas)
|
||||
- [SciPy](https://github.com/scipy/scipy)
|
||||
|
||||
...and many more.
|
||||
...and [many more](#whos-using-ruff).
|
||||
|
||||
Ruff is backed by [Astral](https://astral.sh). Read the [launch post](https://astral.sh/blog/announcing-astral-the-company-behind-ruff),
|
||||
or the original [project announcement](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster).
|
||||
@@ -150,11 +150,12 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.1.4
|
||||
rev: v0.1.6
|
||||
hooks:
|
||||
# Run the Ruff linter.
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
# Run the Ruff formatter.
|
||||
args: [ --fix ]
|
||||
# Run the formatter.
|
||||
- id: ruff-format
|
||||
```
|
||||
|
||||
@@ -376,8 +377,8 @@ Ruff is used by a number of major open-source projects and companies, including:
|
||||
- Anthropic ([Python SDK](https://github.com/anthropics/anthropic-sdk-python))
|
||||
- [Apache Airflow](https://github.com/apache/airflow)
|
||||
- AstraZeneca ([Magnus](https://github.com/AstraZeneca/magnus-core))
|
||||
- Benchling ([Refac](https://github.com/benchling/refac))
|
||||
- [Babel](https://github.com/python-babel/babel)
|
||||
- Benchling ([Refac](https://github.com/benchling/refac))
|
||||
- [Bokeh](https://github.com/bokeh/bokeh)
|
||||
- [Cryptography (PyCA)](https://github.com/pyca/cryptography)
|
||||
- [DVC](https://github.com/iterative/dvc)
|
||||
@@ -388,15 +389,16 @@ Ruff is used by a number of major open-source projects and companies, including:
|
||||
- [Gradio](https://github.com/gradio-app/gradio)
|
||||
- [Great Expectations](https://github.com/great-expectations/great_expectations)
|
||||
- [HTTPX](https://github.com/encode/httpx)
|
||||
- [Hatch](https://github.com/pypa/hatch)
|
||||
- [Home Assistant](https://github.com/home-assistant/core)
|
||||
- Hugging Face ([Transformers](https://github.com/huggingface/transformers),
|
||||
[Datasets](https://github.com/huggingface/datasets),
|
||||
[Diffusers](https://github.com/huggingface/diffusers))
|
||||
- [Hatch](https://github.com/pypa/hatch)
|
||||
- [Home Assistant](https://github.com/home-assistant/core)
|
||||
- ING Bank ([popmon](https://github.com/ing-bank/popmon), [probatus](https://github.com/ing-bank/probatus))
|
||||
- [Ibis](https://github.com/ibis-project/ibis)
|
||||
- [Jupyter](https://github.com/jupyter-server/jupyter_server)
|
||||
- [LangChain](https://github.com/hwchase17/langchain)
|
||||
- [Litestar](https://litestar.dev/)
|
||||
- [LlamaIndex](https://github.com/jerryjliu/llama_index)
|
||||
- Matrix ([Synapse](https://github.com/matrix-org/synapse))
|
||||
- [MegaLinter](https://github.com/oxsecurity/megalinter)
|
||||
@@ -421,20 +423,21 @@ Ruff is used by a number of major open-source projects and companies, including:
|
||||
- [PostHog](https://github.com/PostHog/posthog)
|
||||
- Prefect ([Python SDK](https://github.com/PrefectHQ/prefect), [Marvin](https://github.com/PrefectHQ/marvin))
|
||||
- [PyInstaller](https://github.com/pyinstaller/pyinstaller)
|
||||
- [PyMC-Marketing](https://github.com/pymc-labs/pymc-marketing)
|
||||
- [PyTorch](https://github.com/pytorch/pytorch)
|
||||
- [Pydantic](https://github.com/pydantic/pydantic)
|
||||
- [Pylint](https://github.com/PyCQA/pylint)
|
||||
- [PyMC-Marketing](https://github.com/pymc-labs/pymc-marketing)
|
||||
- [Reflex](https://github.com/reflex-dev/reflex)
|
||||
- [River](https://github.com/online-ml/river)
|
||||
- [Rippling](https://rippling.com)
|
||||
- [Robyn](https://github.com/sansyrox/robyn)
|
||||
- Scale AI ([Launch SDK](https://github.com/scaleapi/launch-python-client))
|
||||
- Snowflake ([SnowCLI](https://github.com/Snowflake-Labs/snowcli))
|
||||
- [Saleor](https://github.com/saleor/saleor)
|
||||
- Scale AI ([Launch SDK](https://github.com/scaleapi/launch-python-client))
|
||||
- [SciPy](https://github.com/scipy/scipy)
|
||||
- Snowflake ([SnowCLI](https://github.com/Snowflake-Labs/snowcli))
|
||||
- [Sphinx](https://github.com/sphinx-doc/sphinx)
|
||||
- [Stable Baselines3](https://github.com/DLR-RM/stable-baselines3)
|
||||
- [Litestar](https://litestar.dev/)
|
||||
- [Starlette](https://github.com/encode/starlette)
|
||||
- [The Algorithms](https://github.com/TheAlgorithms/Python)
|
||||
- [Vega-Altair](https://github.com/altair-viz/altair)
|
||||
- WordPress ([Openverse](https://github.com/WordPress/openverse))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
description = """
|
||||
Convert Flake8 configuration files to Ruff configuration files.
|
||||
"""
|
||||
@@ -19,7 +19,7 @@ ruff_workspace = { path = "../ruff_workspace" }
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
configparser = { version = "3.0.2" }
|
||||
configparser = { version = "3.0.3" }
|
||||
itertools = { workspace = true }
|
||||
log = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
@@ -34,3 +34,6 @@ toml = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.3.0"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -37,7 +37,7 @@ serde_json.workspace = true
|
||||
url = "2.3.1"
|
||||
ureq = "2.8.0"
|
||||
criterion = { version = "0.5.1", default-features = false }
|
||||
codspeed-criterion-compat = { version="2.3.1", default-features = false, optional = true}
|
||||
codspeed-criterion-compat = { version="2.3.3", default-features = false, optional = true}
|
||||
|
||||
[dev-dependencies]
|
||||
ruff_linter.path = "../ruff_linter"
|
||||
@@ -46,6 +46,9 @@ ruff_python_formatter = { path = "../ruff_python_formatter" }
|
||||
ruff_python_index = { path = "../ruff_python_index" }
|
||||
ruff_python_parser = { path = "../ruff_python_parser" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
codspeed = ["codspeed-criterion-compat"]
|
||||
|
||||
|
||||
@@ -20,3 +20,6 @@ seahash = "4.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
ruff_macros = { path = "../ruff_macros" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_cli"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
@@ -28,7 +28,7 @@ ruff_python_trivia = { path = "../ruff_python_trivia" }
|
||||
ruff_workspace = { path = "../ruff_workspace" }
|
||||
ruff_text_size = { path = "../ruff_text_size" }
|
||||
|
||||
annotate-snippets = { version = "0.9.1", features = ["color"] }
|
||||
annotate-snippets = { version = "0.9.2", features = ["color"] }
|
||||
anyhow = { workspace = true }
|
||||
argfile = { version = "0.1.6" }
|
||||
bincode = { version = "1.3.3" }
|
||||
@@ -76,3 +76,6 @@ mimalloc = "0.1.39"
|
||||
|
||||
[target.'cfg(all(not(target_os = "windows"), not(target_os = "openbsd"), any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))'.dependencies]
|
||||
tikv-jemallocator = "0.5.0"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
0
crates/ruff_cli/resources/test/fixtures/include-test/a.py
vendored
Normal file
0
crates/ruff_cli/resources/test/fixtures/include-test/a.py
vendored
Normal file
0
crates/ruff_cli/resources/test/fixtures/include-test/b.py
vendored
Normal file
0
crates/ruff_cli/resources/test/fixtures/include-test/b.py
vendored
Normal file
0
crates/ruff_cli/resources/test/fixtures/include-test/nested-project/e.py
vendored
Normal file
0
crates/ruff_cli/resources/test/fixtures/include-test/nested-project/e.py
vendored
Normal file
2
crates/ruff_cli/resources/test/fixtures/include-test/nested-project/pyproject.toml
vendored
Normal file
2
crates/ruff_cli/resources/test/fixtures/include-test/nested-project/pyproject.toml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
[tool.ruff]
|
||||
select = []
|
||||
2
crates/ruff_cli/resources/test/fixtures/include-test/pyproject.toml
vendored
Normal file
2
crates/ruff_cli/resources/test/fixtures/include-test/pyproject.toml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
[tool.ruff]
|
||||
include = ["a.py", "subdirectory/c.py"]
|
||||
0
crates/ruff_cli/resources/test/fixtures/include-test/subdirectory/c.py
vendored
Normal file
0
crates/ruff_cli/resources/test/fixtures/include-test/subdirectory/c.py
vendored
Normal file
0
crates/ruff_cli/resources/test/fixtures/include-test/subdirectory/d.py
vendored
Normal file
0
crates/ruff_cli/resources/test/fixtures/include-test/subdirectory/d.py
vendored
Normal file
413
crates/ruff_cli/resources/test/fixtures/trailing_semicolon.ipynb
vendored
Normal file
413
crates/ruff_cli/resources/test/fixtures/trailing_semicolon.ipynb
vendored
Normal file
@@ -0,0 +1,413 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "4f8ce941-1492-4d4e-8ab5-70d733fe891a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%config ZMQInteractiveShell.ast_node_interactivity=\"last_expr_or_assign\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "721ec705-0c65-4bfb-9809-7ed8bc534186",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Assignment statement without a semicolon\n",
|
||||
"x = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "de50e495-17e5-41cc-94bd-565757555d7e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Assignment statement with a semicolon\n",
|
||||
"x = 1;\n",
|
||||
"x = 1;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "39e31201-23da-44eb-8684-41bba3663991",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"2"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Augmented assignment without a semicolon\n",
|
||||
"x += 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "6b73d3dd-c73a-4697-9e97-e109a6c1fbab",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Augmented assignment without a semicolon\n",
|
||||
"x += 1;\n",
|
||||
"x += 1; # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "2a3e5b86-aa5b-46ba-b9c6-0386d876f58c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Multiple assignment without a semicolon\n",
|
||||
"x = y = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "07f89e51-9357-4cfb-8fc5-76fb75e35949",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Multiple assignment with a semicolon\n",
|
||||
"x = y = 1;\n",
|
||||
"x = y = 1;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "c22b539d-473e-48f8-a236-625e58c47a00",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Tuple unpacking without a semicolon\n",
|
||||
"x, y = 1, 2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "12c87940-a0d5-403b-a81c-7507eb06dc7e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Tuple unpacking with a semicolon (irrelevant)\n",
|
||||
"x, y = 1, 2;\n",
|
||||
"x, y = 1, 2; # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "5a768c76-6bc4-470c-b37e-8cc14bc6caf4",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Annotated assignment statement without a semicolon\n",
|
||||
"x: int = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "21bfda82-1a9a-4ba1-9078-74ac480804b5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Annotated assignment statement without a semicolon\n",
|
||||
"x: int = 1;\n",
|
||||
"x: int = 1; # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "09929999-ff29-4d10-ad2b-e665af15812d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Assignment expression without a semicolon\n",
|
||||
"(x := 1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "32a83217-1bad-4f61-855e-ffcdb119c763",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Assignment expression with a semicolon\n",
|
||||
"(x := 1);\n",
|
||||
"(x := 1); # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "61b81865-277e-4964-b03e-eb78f1f318eb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"x = 1\n",
|
||||
"# Expression without a semicolon\n",
|
||||
"x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "974c29be-67e1-4000-95fa-6ca118a63bad",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"x = 1\n",
|
||||
"# Expression with a semicolon\n",
|
||||
"x;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "cfeb1757-46d6-4f13-969f-a283b6d0304f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Point:\n",
|
||||
" def __init__(self, x, y):\n",
|
||||
" self.x = x\n",
|
||||
" self.y = y\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"p = Point(0, 0);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "2ee7f1a5-ccfe-4004-bfa4-ef834a58da97",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Assignment statement where the left is an attribute access doesn't\n",
|
||||
"# print the value.\n",
|
||||
"p.x = 1;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"id": "3e49370a-048b-474d-aa0a-3d1d4a73ad37",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"data = {}\n",
|
||||
"\n",
|
||||
"# Neither does the subscript node\n",
|
||||
"data[\"foo\"] = 1;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"id": "d594bdd3-eaa9-41ef-8cda-cf01bc273b2d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if (x := 1):\n",
|
||||
" # It should be the top level statement\n",
|
||||
" x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"id": "e532f0cf-80c7-42b7-8226-6002fcf74fb6",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Parentheses with comments\n",
|
||||
"(\n",
|
||||
" x := 1 # comment\n",
|
||||
") # comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"id": "473c5d62-871b-46ed-8a34-27095243f462",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Parentheses with comments\n",
|
||||
"(\n",
|
||||
" x := 1 # comment\n",
|
||||
"); # comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"id": "8c3c2361-f49f-45fe-bbe3-7e27410a8a86",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'Hello world!'"
|
||||
]
|
||||
},
|
||||
"execution_count": 22,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\"\"\"Hello world!\"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"id": "23dbe9b5-3f68-4890-ab2d-ab0dbfd0712a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\"\"\"Hello world!\"\"\"; # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"id": "3ce33108-d95d-4c70-83d1-0d4fd36a2951",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'x = 1'"
|
||||
]
|
||||
},
|
||||
"execution_count": 24,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"x = 1\n",
|
||||
"f\"x = {x}\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"id": "654a4a67-de43-4684-824a-9451c67db48f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"x = 1\n",
|
||||
"f\"x = {x}\";\n",
|
||||
"f\"x = {x}\"; # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python (ruff-playground)",
|
||||
"language": "python",
|
||||
"name": "ruff-playground"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -8,8 +8,8 @@ use ruff_linter::line_width::LineLength;
|
||||
use ruff_linter::logging::LogLevel;
|
||||
use ruff_linter::registry::Rule;
|
||||
use ruff_linter::settings::types::{
|
||||
FilePattern, PatternPrefixPair, PerFileIgnore, PreviewMode, PythonVersion, SerializationFormat,
|
||||
UnsafeFixes,
|
||||
ExtensionPair, FilePattern, PatternPrefixPair, PerFileIgnore, PreviewMode, PythonVersion,
|
||||
SerializationFormat, UnsafeFixes,
|
||||
};
|
||||
use ruff_linter::{RuleParser, RuleSelector, RuleSelectorParser};
|
||||
use ruff_workspace::configuration::{Configuration, RuleSelection};
|
||||
@@ -88,6 +88,7 @@ pub enum Command {
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct CheckCommand {
|
||||
/// List of files or directories to check.
|
||||
#[clap(help = "List of files or directories to check [default: .]")]
|
||||
pub files: Vec<PathBuf>,
|
||||
/// Apply fixes to resolve lint violations.
|
||||
/// Use `--no-fix` to disable or `--unsafe-fixes` to include unsafe fixes.
|
||||
@@ -351,6 +352,9 @@ pub struct CheckCommand {
|
||||
conflicts_with = "watch",
|
||||
)]
|
||||
pub show_settings: bool,
|
||||
/// List of mappings from file extension to language (one of ["python", "ipynb", "pyi"]).
|
||||
#[arg(long, value_delimiter = ',', hide = true)]
|
||||
pub extension: Option<Vec<ExtensionPair>>,
|
||||
/// Dev-only argument to show fixes
|
||||
#[arg(long, hide = true)]
|
||||
pub ecosystem_ci: bool,
|
||||
@@ -360,6 +364,7 @@ pub struct CheckCommand {
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct FormatCommand {
|
||||
/// List of files or directories to format.
|
||||
#[clap(help = "List of files or directories to format [default: .]")]
|
||||
pub files: Vec<PathBuf>,
|
||||
/// Avoid writing any formatted files back; instead, exit with a non-zero status code if any
|
||||
/// files would have been modified, and zero otherwise.
|
||||
@@ -535,6 +540,7 @@ impl CheckCommand {
|
||||
force_exclude: resolve_bool_arg(self.force_exclude, self.no_force_exclude),
|
||||
output_format: self.output_format,
|
||||
show_fixes: resolve_bool_arg(self.show_fixes, self.no_show_fixes),
|
||||
extension: self.extension,
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -647,6 +653,7 @@ pub struct CliOverrides {
|
||||
pub force_exclude: Option<bool>,
|
||||
pub output_format: Option<SerializationFormat>,
|
||||
pub show_fixes: Option<bool>,
|
||||
pub extension: Option<Vec<ExtensionPair>>,
|
||||
}
|
||||
|
||||
impl ConfigurationTransformer for CliOverrides {
|
||||
@@ -731,6 +738,9 @@ impl ConfigurationTransformer for CliOverrides {
|
||||
if let Some(target_version) = &self.target_version {
|
||||
config.target_version = Some(*target_version);
|
||||
}
|
||||
if let Some(extension) = &self.extension {
|
||||
config.lint.extension = Some(extension.clone().into_iter().collect());
|
||||
}
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ use crate::diagnostics::Diagnostics;
|
||||
use crate::panic::catch_unwind;
|
||||
|
||||
/// Run the linter over a collection of files.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn check(
|
||||
files: &[PathBuf],
|
||||
pyproject_config: &PyprojectConfig,
|
||||
@@ -184,6 +185,7 @@ pub(crate) fn check(
|
||||
|
||||
/// Wraps [`lint_path`](crate::diagnostics::lint_path) in a [`catch_unwind`](std::panic::catch_unwind) and emits
|
||||
/// a diagnostic if the linting the file panics.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn lint_path(
|
||||
path: &Path,
|
||||
package: Option<&Path>,
|
||||
@@ -200,12 +202,12 @@ fn lint_path(
|
||||
match result {
|
||||
Ok(inner) => inner,
|
||||
Err(error) => {
|
||||
let message = r#"This indicates a bug in Ruff. If you could open an issue at:
|
||||
let message = r"This indicates a bug in Ruff. If you could open an issue at:
|
||||
|
||||
https://github.com/astral-sh/ruff/issues/new?title=%5BLinter%20panic%5D
|
||||
|
||||
...with the relevant file contents, the `pyproject.toml` settings, and the following stack trace, we'd be very appreciative!
|
||||
"#;
|
||||
";
|
||||
|
||||
error!(
|
||||
"{}{}{} {message}\n{error}",
|
||||
|
||||
@@ -8,7 +8,7 @@ use ruff_workspace::resolver::{match_exclusion, python_file_at_path, PyprojectCo
|
||||
|
||||
use crate::args::CliOverrides;
|
||||
use crate::diagnostics::{lint_stdin, Diagnostics};
|
||||
use crate::stdin::read_from_stdin;
|
||||
use crate::stdin::{parrot_stdin, read_from_stdin};
|
||||
|
||||
/// Run the linter over a single file, read from `stdin`.
|
||||
pub(crate) fn check_stdin(
|
||||
@@ -21,6 +21,9 @@ pub(crate) fn check_stdin(
|
||||
if pyproject_config.settings.file_resolver.force_exclude {
|
||||
if let Some(filename) = filename {
|
||||
if !python_file_at_path(filename, pyproject_config, overrides)? {
|
||||
if fix_mode.is_apply() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(Diagnostics::default());
|
||||
}
|
||||
|
||||
@@ -29,14 +32,17 @@ pub(crate) fn check_stdin(
|
||||
.file_name()
|
||||
.is_some_and(|name| match_exclusion(filename, name, &lint_settings.exclude))
|
||||
{
|
||||
if fix_mode.is_apply() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(Diagnostics::default());
|
||||
}
|
||||
}
|
||||
}
|
||||
let stdin = read_from_stdin()?;
|
||||
let package_root = filename.and_then(Path::parent).and_then(|path| {
|
||||
packaging::detect_package_root(path, &pyproject_config.settings.linter.namespace_packages)
|
||||
});
|
||||
let stdin = read_from_stdin()?;
|
||||
let mut diagnostics = lint_stdin(
|
||||
filename,
|
||||
package_root,
|
||||
|
||||
@@ -34,7 +34,7 @@ use crate::args::{CliOverrides, FormatArguments};
|
||||
use crate::cache::{Cache, FileCacheKey, PackageCacheMap, PackageCaches};
|
||||
use crate::panic::{catch_unwind, PanicError};
|
||||
use crate::resolve::resolve;
|
||||
use crate::ExitStatus;
|
||||
use crate::{resolve_default_files, ExitStatus};
|
||||
|
||||
#[derive(Debug, Copy, Clone, is_macro::Is)]
|
||||
pub(crate) enum FormatMode {
|
||||
@@ -60,7 +60,7 @@ impl FormatMode {
|
||||
|
||||
/// Format a set of files, and return the exit status.
|
||||
pub(crate) fn format(
|
||||
cli: &FormatArguments,
|
||||
cli: FormatArguments,
|
||||
overrides: &CliOverrides,
|
||||
log_level: LogLevel,
|
||||
) -> Result<ExitStatus> {
|
||||
@@ -70,8 +70,9 @@ pub(crate) fn format(
|
||||
overrides,
|
||||
cli.stdin_filename.as_deref(),
|
||||
)?;
|
||||
let mode = FormatMode::from_cli(cli);
|
||||
let (paths, resolver) = python_files_in_path(&cli.files, &pyproject_config, overrides)?;
|
||||
let mode = FormatMode::from_cli(&cli);
|
||||
let files = resolve_default_files(cli.files, false);
|
||||
let (paths, resolver) = python_files_in_path(&files, &pyproject_config, overrides)?;
|
||||
|
||||
if paths.is_empty() {
|
||||
warn_user_once!("No Python files found under the given path(s)");
|
||||
@@ -660,12 +661,12 @@ impl Display for FormatCommandError {
|
||||
}
|
||||
}
|
||||
Self::Panic(path, err) => {
|
||||
let message = r#"This indicates a bug in Ruff. If you could open an issue at:
|
||||
let message = r"This indicates a bug in Ruff. If you could open an issue at:
|
||||
|
||||
https://github.com/astral-sh/ruff/issues/new?title=%5BFormatter%20panic%5D
|
||||
|
||||
...with the relevant file contents, the `pyproject.toml` settings, and the following stack trace, we'd be very appreciative!
|
||||
"#;
|
||||
";
|
||||
if let Some(path) = path {
|
||||
write!(
|
||||
f,
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::commands::format::{
|
||||
FormatResult, FormattedSource,
|
||||
};
|
||||
use crate::resolve::resolve;
|
||||
use crate::stdin::read_from_stdin;
|
||||
use crate::stdin::{parrot_stdin, read_from_stdin};
|
||||
use crate::ExitStatus;
|
||||
|
||||
/// Run the formatter over a single file, read from `stdin`.
|
||||
@@ -34,6 +34,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
||||
if pyproject_config.settings.file_resolver.force_exclude {
|
||||
if let Some(filename) = cli.stdin_filename.as_deref() {
|
||||
if !python_file_at_path(filename, &pyproject_config, overrides)? {
|
||||
if mode.is_write() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(ExitStatus::Success);
|
||||
}
|
||||
|
||||
@@ -42,6 +45,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
||||
.file_name()
|
||||
.is_some_and(|name| match_exclusion(filename, name, &format_settings.exclude))
|
||||
{
|
||||
if mode.is_write() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(ExitStatus::Success);
|
||||
}
|
||||
}
|
||||
@@ -50,6 +56,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
||||
let path = cli.stdin_filename.as_deref();
|
||||
|
||||
let SourceType::Python(source_type) = path.map(SourceType::from).unwrap_or_default() else {
|
||||
if mode.is_write() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(ExitStatus::Success);
|
||||
};
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ fn format_rule_text(rule: Rule) -> String {
|
||||
|
||||
if rule.is_preview() || rule.is_nursery() {
|
||||
output.push_str(
|
||||
r#"This rule is in preview and is not stable. The `--preview` flag is required for use."#,
|
||||
r"This rule is in preview and is not stable. The `--preview` flag is required for use.",
|
||||
);
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
|
||||
@@ -17,13 +17,13 @@ use ruff_linter::logging::DisplayParseError;
|
||||
use ruff_linter::message::Message;
|
||||
use ruff_linter::pyproject_toml::lint_pyproject_toml;
|
||||
use ruff_linter::registry::AsRule;
|
||||
use ruff_linter::settings::types::UnsafeFixes;
|
||||
use ruff_linter::settings::types::{ExtensionMapping, UnsafeFixes};
|
||||
use ruff_linter::settings::{flags, LinterSettings};
|
||||
use ruff_linter::source_kind::{SourceError, SourceKind};
|
||||
use ruff_linter::{fs, IOError, SyntaxError};
|
||||
use ruff_notebook::{Notebook, NotebookError, NotebookIndex};
|
||||
use ruff_python_ast::imports::ImportMap;
|
||||
use ruff_python_ast::{SourceType, TomlSourceType};
|
||||
use ruff_python_ast::{PySourceType, SourceType, TomlSourceType};
|
||||
use ruff_source_file::{LineIndex, SourceCode, SourceFileBuilder};
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ruff_workspace::Settings;
|
||||
@@ -177,6 +177,11 @@ impl AddAssign for FixMap {
|
||||
}
|
||||
}
|
||||
|
||||
fn override_source_type(path: Option<&Path>, extension: &ExtensionMapping) -> Option<PySourceType> {
|
||||
let ext = path?.extension()?.to_str()?;
|
||||
extension.get(ext).map(PySourceType::from)
|
||||
}
|
||||
|
||||
/// Lint the source code at the given `Path`.
|
||||
pub(crate) fn lint_path(
|
||||
path: &Path,
|
||||
@@ -221,31 +226,35 @@ pub(crate) fn lint_path(
|
||||
|
||||
debug!("Checking: {}", path.display());
|
||||
|
||||
let source_type = match SourceType::from(path) {
|
||||
SourceType::Toml(TomlSourceType::Pyproject) => {
|
||||
let messages = if settings
|
||||
.rules
|
||||
.iter_enabled()
|
||||
.any(|rule_code| rule_code.lint_source().is_pyproject_toml())
|
||||
{
|
||||
let contents = match std::fs::read_to_string(path).map_err(SourceError::from) {
|
||||
Ok(contents) => contents,
|
||||
Err(err) => {
|
||||
return Ok(Diagnostics::from_source_error(&err, Some(path), settings));
|
||||
}
|
||||
let source_type = match override_source_type(Some(path), &settings.extension) {
|
||||
Some(source_type) => source_type,
|
||||
None => match SourceType::from(path) {
|
||||
SourceType::Toml(TomlSourceType::Pyproject) => {
|
||||
let messages = if settings
|
||||
.rules
|
||||
.iter_enabled()
|
||||
.any(|rule_code| rule_code.lint_source().is_pyproject_toml())
|
||||
{
|
||||
let contents = match std::fs::read_to_string(path).map_err(SourceError::from) {
|
||||
Ok(contents) => contents,
|
||||
Err(err) => {
|
||||
return Ok(Diagnostics::from_source_error(&err, Some(path), settings));
|
||||
}
|
||||
};
|
||||
let source_file =
|
||||
SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
|
||||
lint_pyproject_toml(source_file, settings)
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
let source_file = SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
|
||||
lint_pyproject_toml(source_file, settings)
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
return Ok(Diagnostics {
|
||||
messages,
|
||||
..Diagnostics::default()
|
||||
});
|
||||
}
|
||||
SourceType::Toml(_) => return Ok(Diagnostics::default()),
|
||||
SourceType::Python(source_type) => source_type,
|
||||
return Ok(Diagnostics {
|
||||
messages,
|
||||
..Diagnostics::default()
|
||||
});
|
||||
}
|
||||
SourceType::Toml(_) => return Ok(Diagnostics::default()),
|
||||
SourceType::Python(source_type) => source_type,
|
||||
},
|
||||
};
|
||||
|
||||
// Extract the sources from the file.
|
||||
@@ -370,8 +379,15 @@ pub(crate) fn lint_stdin(
|
||||
fix_mode: flags::FixMode,
|
||||
) -> Result<Diagnostics> {
|
||||
// TODO(charlie): Support `pyproject.toml`.
|
||||
let SourceType::Python(source_type) = path.map(SourceType::from).unwrap_or_default() else {
|
||||
return Ok(Diagnostics::default());
|
||||
let source_type = if let Some(source_type) =
|
||||
override_source_type(path, &settings.linter.extension)
|
||||
{
|
||||
source_type
|
||||
} else {
|
||||
let SourceType::Python(source_type) = path.map(SourceType::from).unwrap_or_default() else {
|
||||
return Ok(Diagnostics::default());
|
||||
};
|
||||
source_type
|
||||
};
|
||||
|
||||
// Extract the sources from the file.
|
||||
|
||||
@@ -101,6 +101,19 @@ fn is_stdin(files: &[PathBuf], stdin_filename: Option<&Path>) -> bool {
|
||||
file == Path::new("-")
|
||||
}
|
||||
|
||||
/// Returns the default set of files if none are provided, otherwise returns `None`.
|
||||
fn resolve_default_files(files: Vec<PathBuf>, is_stdin: bool) -> Vec<PathBuf> {
|
||||
if files.is_empty() {
|
||||
if is_stdin {
|
||||
vec![Path::new("-").to_path_buf()]
|
||||
} else {
|
||||
vec![Path::new(".").to_path_buf()]
|
||||
}
|
||||
} else {
|
||||
files
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the actual value of the `format` desired from either `output_format`
|
||||
/// or `format`, and warn the user if they're using the deprecated form.
|
||||
fn resolve_help_output_format(output_format: HelpFormat, format: Option<HelpFormat>) -> HelpFormat {
|
||||
@@ -196,7 +209,7 @@ fn format(args: FormatCommand, log_level: LogLevel) -> Result<ExitStatus> {
|
||||
if is_stdin(&cli.files, cli.stdin_filename.as_deref()) {
|
||||
commands::format_stdin::format_stdin(&cli, &overrides)
|
||||
} else {
|
||||
commands::format::format(&cli, &overrides, log_level)
|
||||
commands::format::format(cli, &overrides, log_level)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,17 +235,15 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
|
||||
};
|
||||
let stderr_writer = Box::new(BufWriter::new(io::stderr()));
|
||||
|
||||
let is_stdin = is_stdin(&cli.files, cli.stdin_filename.as_deref());
|
||||
let files = resolve_default_files(cli.files, is_stdin);
|
||||
|
||||
if cli.show_settings {
|
||||
commands::show_settings::show_settings(
|
||||
&cli.files,
|
||||
&pyproject_config,
|
||||
&overrides,
|
||||
&mut writer,
|
||||
)?;
|
||||
commands::show_settings::show_settings(&files, &pyproject_config, &overrides, &mut writer)?;
|
||||
return Ok(ExitStatus::Success);
|
||||
}
|
||||
if cli.show_files {
|
||||
commands::show_files::show_files(&cli.files, &pyproject_config, &overrides, &mut writer)?;
|
||||
commands::show_files::show_files(&files, &pyproject_config, &overrides, &mut writer)?;
|
||||
return Ok(ExitStatus::Success);
|
||||
}
|
||||
|
||||
@@ -295,8 +306,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
|
||||
if !fix_mode.is_generate() {
|
||||
warn_user!("--fix is incompatible with --add-noqa.");
|
||||
}
|
||||
let modifications =
|
||||
commands::add_noqa::add_noqa(&cli.files, &pyproject_config, &overrides)?;
|
||||
let modifications = commands::add_noqa::add_noqa(&files, &pyproject_config, &overrides)?;
|
||||
if modifications > 0 && log_level >= LogLevel::Default {
|
||||
let s = if modifications == 1 { "" } else { "s" };
|
||||
#[allow(clippy::print_stderr)]
|
||||
@@ -323,7 +333,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
|
||||
// Configure the file watcher.
|
||||
let (tx, rx) = channel();
|
||||
let mut watcher = recommended_watcher(tx)?;
|
||||
for file in &cli.files {
|
||||
for file in &files {
|
||||
watcher.watch(file, RecursiveMode::Recursive)?;
|
||||
}
|
||||
if let Some(file) = pyproject_config.path.as_ref() {
|
||||
@@ -335,7 +345,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
|
||||
printer.write_to_user("Starting linter in watch mode...\n");
|
||||
|
||||
let messages = commands::check::check(
|
||||
&cli.files,
|
||||
&files,
|
||||
&pyproject_config,
|
||||
&overrides,
|
||||
cache.into(),
|
||||
@@ -368,7 +378,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
|
||||
printer.write_to_user("File change detected...\n");
|
||||
|
||||
let messages = commands::check::check(
|
||||
&cli.files,
|
||||
&files,
|
||||
&pyproject_config,
|
||||
&overrides,
|
||||
cache.into(),
|
||||
@@ -382,8 +392,6 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let is_stdin = is_stdin(&cli.files, cli.stdin_filename.as_deref());
|
||||
|
||||
// Generate lint violations.
|
||||
let diagnostics = if is_stdin {
|
||||
commands::check_stdin::check_stdin(
|
||||
@@ -395,7 +403,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
|
||||
)?
|
||||
} else {
|
||||
commands::check::check(
|
||||
&cli.files,
|
||||
&files,
|
||||
&pyproject_config,
|
||||
&overrides,
|
||||
cache.into(),
|
||||
|
||||
@@ -43,7 +43,7 @@ pub fn resolve(
|
||||
{
|
||||
let settings = resolve_root_settings(&pyproject, Relativity::Cwd, overrides)?;
|
||||
debug!(
|
||||
"Using user specified pyproject.toml at {}",
|
||||
"Using user-specified configuration file at: {}",
|
||||
pyproject.display()
|
||||
);
|
||||
return Ok(PyprojectConfig::new(
|
||||
@@ -63,7 +63,10 @@ pub fn resolve(
|
||||
.as_ref()
|
||||
.unwrap_or(&path_dedot::CWD.as_path()),
|
||||
)? {
|
||||
debug!("Using pyproject.toml (parent) at {}", pyproject.display());
|
||||
debug!(
|
||||
"Using configuration file (via parent) at: {}",
|
||||
pyproject.display()
|
||||
);
|
||||
let settings = resolve_root_settings(&pyproject, Relativity::Parent, overrides)?;
|
||||
return Ok(PyprojectConfig::new(
|
||||
PyprojectDiscoveryStrategy::Hierarchical,
|
||||
@@ -77,7 +80,10 @@ pub fn resolve(
|
||||
// end up the "closest" `pyproject.toml` file for every Python file later on, so
|
||||
// these act as the "default" settings.)
|
||||
if let Some(pyproject) = pyproject::find_user_settings_toml() {
|
||||
debug!("Using pyproject.toml (cwd) at {}", pyproject.display());
|
||||
debug!(
|
||||
"Using configuration file (via cwd) at: {}",
|
||||
pyproject.display()
|
||||
);
|
||||
let settings = resolve_root_settings(&pyproject, Relativity::Cwd, overrides)?;
|
||||
return Ok(PyprojectConfig::new(
|
||||
PyprojectDiscoveryStrategy::Hierarchical,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
/// Read a string from `stdin`.
|
||||
pub(crate) fn read_from_stdin() -> Result<String, io::Error> {
|
||||
@@ -7,3 +7,11 @@ pub(crate) fn read_from_stdin() -> Result<String, io::Error> {
|
||||
io::stdin().lock().read_to_string(&mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
/// Read bytes from `stdin` and write them to `stdout`.
|
||||
pub(crate) fn parrot_stdin() -> Result<(), io::Error> {
|
||||
let mut buffer = String::new();
|
||||
io::stdin().lock().read_to_string(&mut buffer)?;
|
||||
io::stdout().write_all(buffer.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -43,6 +43,53 @@ if condition:
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_files() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
fs::write(
|
||||
tempdir.path().join("foo.py"),
|
||||
r#"
|
||||
foo = "needs formatting"
|
||||
"#,
|
||||
)?;
|
||||
fs::write(
|
||||
tempdir.path().join("bar.py"),
|
||||
r#"
|
||||
bar = "needs formatting"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["format", "--isolated", "--no-cache", "--check"]).current_dir(tempdir.path()), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
Would reformat: bar.py
|
||||
Would reformat: foo.py
|
||||
2 files would be reformatted
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_warn_stdin_filename_with_files() {
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["format", "--isolated", "--stdin-filename", "foo.py"])
|
||||
.arg("foo.py")
|
||||
.pass_stdin("foo = 1"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
foo = 1
|
||||
|
||||
----- stderr -----
|
||||
warning: Ignoring file foo.py in favor of standard input.
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_options() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
@@ -320,6 +367,11 @@ if __name__ == '__main__':
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
from test import say_hy
|
||||
|
||||
if __name__ == '__main__':
|
||||
say_hy("dear Ruff contributor")
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
Ok(())
|
||||
@@ -390,9 +442,9 @@ fn deprecated_options() -> Result<()> {
|
||||
let ruff_toml = tempdir.path().join("ruff.toml");
|
||||
fs::write(
|
||||
&ruff_toml,
|
||||
r#"
|
||||
r"
|
||||
tab-size = 2
|
||||
"#,
|
||||
",
|
||||
)?;
|
||||
|
||||
insta::with_settings!({filters => vec![
|
||||
@@ -402,10 +454,10 @@ tab-size = 2
|
||||
.args(["format", "--config"])
|
||||
.arg(&ruff_toml)
|
||||
.arg("-")
|
||||
.pass_stdin(r#"
|
||||
.pass_stdin(r"
|
||||
if True:
|
||||
pass
|
||||
"#), @r###"
|
||||
"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
@@ -438,9 +490,9 @@ format = "json"
|
||||
.args(["check", "--select", "F401", "--no-cache", "--config"])
|
||||
.arg(&ruff_toml)
|
||||
.arg("-")
|
||||
.pass_stdin(r#"
|
||||
.pass_stdin(r"
|
||||
import os
|
||||
"#), @r###"
|
||||
"), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
@@ -813,3 +865,432 @@ fn test_diff_stdin_formatted() {
|
||||
----- stderr -----
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_notebook_trailing_semicolon() {
|
||||
let fixtures = Path::new("resources").join("test").join("fixtures");
|
||||
let unformatted = fs::read(fixtures.join("trailing_semicolon.ipynb")).unwrap();
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["format", "--isolated", "--stdin-filename", "test.ipynb"])
|
||||
.arg("-")
|
||||
.pass_stdin(unformatted), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "4f8ce941-1492-4d4e-8ab5-70d733fe891a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%config ZMQInteractiveShell.ast_node_interactivity=\"last_expr_or_assign\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "721ec705-0c65-4bfb-9809-7ed8bc534186",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Assignment statement without a semicolon\n",
|
||||
"x = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "de50e495-17e5-41cc-94bd-565757555d7e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Assignment statement with a semicolon\n",
|
||||
"x = 1\n",
|
||||
"x = 1;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "39e31201-23da-44eb-8684-41bba3663991",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"2"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Augmented assignment without a semicolon\n",
|
||||
"x += 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "6b73d3dd-c73a-4697-9e97-e109a6c1fbab",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Augmented assignment without a semicolon\n",
|
||||
"x += 1\n",
|
||||
"x += 1; # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "2a3e5b86-aa5b-46ba-b9c6-0386d876f58c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Multiple assignment without a semicolon\n",
|
||||
"x = y = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "07f89e51-9357-4cfb-8fc5-76fb75e35949",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Multiple assignment with a semicolon\n",
|
||||
"x = y = 1\n",
|
||||
"x = y = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "c22b539d-473e-48f8-a236-625e58c47a00",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Tuple unpacking without a semicolon\n",
|
||||
"x, y = 1, 2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "12c87940-a0d5-403b-a81c-7507eb06dc7e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Tuple unpacking with a semicolon (irrelevant)\n",
|
||||
"x, y = 1, 2\n",
|
||||
"x, y = 1, 2 # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "5a768c76-6bc4-470c-b37e-8cc14bc6caf4",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Annotated assignment statement without a semicolon\n",
|
||||
"x: int = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "21bfda82-1a9a-4ba1-9078-74ac480804b5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Annotated assignment statement without a semicolon\n",
|
||||
"x: int = 1\n",
|
||||
"x: int = 1; # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "09929999-ff29-4d10-ad2b-e665af15812d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Assignment expression without a semicolon\n",
|
||||
"(x := 1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "32a83217-1bad-4f61-855e-ffcdb119c763",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Assignment expression with a semicolon\n",
|
||||
"(x := 1)\n",
|
||||
"(x := 1); # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "61b81865-277e-4964-b03e-eb78f1f318eb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"x = 1\n",
|
||||
"# Expression without a semicolon\n",
|
||||
"x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "974c29be-67e1-4000-95fa-6ca118a63bad",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"x = 1\n",
|
||||
"# Expression with a semicolon\n",
|
||||
"x;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "cfeb1757-46d6-4f13-969f-a283b6d0304f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Point:\n",
|
||||
" def __init__(self, x, y):\n",
|
||||
" self.x = x\n",
|
||||
" self.y = y\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"p = Point(0, 0);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "2ee7f1a5-ccfe-4004-bfa4-ef834a58da97",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Assignment statement where the left is an attribute access doesn't\n",
|
||||
"# print the value.\n",
|
||||
"p.x = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"id": "3e49370a-048b-474d-aa0a-3d1d4a73ad37",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"data = {}\n",
|
||||
"\n",
|
||||
"# Neither does the subscript node\n",
|
||||
"data[\"foo\"] = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"id": "d594bdd3-eaa9-41ef-8cda-cf01bc273b2d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if x := 1:\n",
|
||||
" # It should be the top level statement\n",
|
||||
" x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"id": "e532f0cf-80c7-42b7-8226-6002fcf74fb6",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Parentheses with comments\n",
|
||||
"(\n",
|
||||
" x := 1 # comment\n",
|
||||
") # comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"id": "473c5d62-871b-46ed-8a34-27095243f462",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Parentheses with comments\n",
|
||||
"(\n",
|
||||
" x := 1 # comment\n",
|
||||
"); # comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"id": "8c3c2361-f49f-45fe-bbe3-7e27410a8a86",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'Hello world!'"
|
||||
]
|
||||
},
|
||||
"execution_count": 22,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\"\"\"Hello world!\"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"id": "23dbe9b5-3f68-4890-ab2d-ab0dbfd0712a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\"\"\"Hello world!\"\"\"; # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"id": "3ce33108-d95d-4c70-83d1-0d4fd36a2951",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'x = 1'"
|
||||
]
|
||||
},
|
||||
"execution_count": 24,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"x = 1\n",
|
||||
"f\"x = {x}\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"id": "654a4a67-de43-4684-824a-9451c67db48f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"x = 1\n",
|
||||
"f\"x = {x}\"\n",
|
||||
"f\"x = {x}\"; # comment\n",
|
||||
"# comment"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python (ruff-playground)",
|
||||
"language": "python",
|
||||
"name": "ruff-playground"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
101
crates/ruff_cli/tests/resolve_files.rs
Normal file
101
crates/ruff_cli/tests/resolve_files.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
#![cfg(not(target_family = "wasm"))]
|
||||
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
|
||||
use insta_cmd::{assert_cmd_snapshot, get_cargo_bin};
|
||||
const BIN_NAME: &str = "ruff";
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const TEST_FILTERS: &[(&str, &str)] = &[(".*/resources/test/fixtures/", "[BASEPATH]/")];
|
||||
#[cfg(target_os = "windows")]
|
||||
const TEST_FILTERS: &[(&str, &str)] = &[
|
||||
(r".*\\resources\\test\\fixtures\\", "[BASEPATH]\\"),
|
||||
(r"\\", "/"),
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn check_project_include_defaults() {
|
||||
// Defaults to checking the current working directory
|
||||
//
|
||||
// The test directory includes:
|
||||
// - A pyproject.toml which specifies an include
|
||||
// - A nested pyproject.toml which has a Ruff section
|
||||
//
|
||||
// The nested project should all be checked instead of respecting the parent includes
|
||||
|
||||
insta::with_settings!({
|
||||
filters => TEST_FILTERS.to_vec()
|
||||
}, {
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["check", "--show-files"]).current_dir(Path::new("./resources/test/fixtures/include-test")), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
[BASEPATH]/include-test/a.py
|
||||
[BASEPATH]/include-test/nested-project/e.py
|
||||
[BASEPATH]/include-test/nested-project/pyproject.toml
|
||||
[BASEPATH]/include-test/subdirectory/c.py
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_project_respects_direct_paths() {
|
||||
// Given a direct path not included in the project `includes`, it should be checked
|
||||
|
||||
insta::with_settings!({
|
||||
filters => TEST_FILTERS.to_vec()
|
||||
}, {
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["check", "--show-files", "b.py"]).current_dir(Path::new("./resources/test/fixtures/include-test")), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
[BASEPATH]/include-test/b.py
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_project_respects_subdirectory_includes() {
|
||||
// Given a direct path to a subdirectory, the include should be respected
|
||||
|
||||
insta::with_settings!({
|
||||
filters => TEST_FILTERS.to_vec()
|
||||
}, {
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["check", "--show-files", "subdirectory"]).current_dir(Path::new("./resources/test/fixtures/include-test")), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
[BASEPATH]/include-test/subdirectory/c.py
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_project_from_project_subdirectory_respects_includes() {
|
||||
// Run from a project subdirectory, the include specified in the parent directory should be respected
|
||||
|
||||
insta::with_settings!({
|
||||
filters => TEST_FILTERS.to_vec()
|
||||
}, {
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["check", "--show-files"]).current_dir(Path::new("./resources/test/fixtures/include-test/subdirectory")), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
[BASEPATH]/include-test/subdirectory/c.py
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
});
|
||||
}
|
||||
@@ -48,9 +48,12 @@ tracing-indicatif = { workspace = true }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
imara-diff = "0.1.5"
|
||||
|
||||
[dev-dependencies]
|
||||
indoc = "2.0.4"
|
||||
|
||||
[features]
|
||||
# Turn off rayon for profiling
|
||||
singlethreaded = []
|
||||
|
||||
[dev-dependencies]
|
||||
indoc = "2.0.4"
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -49,7 +49,7 @@ pub(crate) fn main(args: &Args) -> Result<()> {
|
||||
|
||||
if rule.is_preview() || rule.is_nursery() {
|
||||
output.push_str(
|
||||
r#"This rule is unstable and in [preview](../preview.md). The `--preview` flag is required for use."#,
|
||||
r"This rule is unstable and in [preview](../preview.md). The `--preview` flag is required for use.",
|
||||
);
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
|
||||
@@ -129,12 +129,12 @@ fn emit_field(output: &mut String, name: &str, field: &OptionField, parent_set:
|
||||
output.push_str("**Example usage**:\n\n");
|
||||
output.push_str(&format_tab(
|
||||
"pyproject.toml",
|
||||
&format_header(parent_set, ConfigurationFile::PyprojectToml),
|
||||
&format_header(field.scope, parent_set, ConfigurationFile::PyprojectToml),
|
||||
field.example,
|
||||
));
|
||||
output.push_str(&format_tab(
|
||||
"ruff.toml",
|
||||
&format_header(parent_set, ConfigurationFile::RuffToml),
|
||||
&format_header(field.scope, parent_set, ConfigurationFile::RuffToml),
|
||||
field.example,
|
||||
));
|
||||
output.push('\n');
|
||||
@@ -149,23 +149,53 @@ fn format_tab(tab_name: &str, header: &str, content: &str) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
fn format_header(parent_set: &Set, configuration: ConfigurationFile) -> String {
|
||||
let fmt = if let Some(set_name) = parent_set.name() {
|
||||
if set_name == "format" {
|
||||
String::from(".format")
|
||||
} else {
|
||||
format!(".lint.{set_name}")
|
||||
}
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
/// Format the TOML header for the example usage for a given option.
|
||||
///
|
||||
/// For example: `[tool.ruff.format]` or `[tool.ruff.lint.isort]`.
|
||||
fn format_header(
|
||||
scope: Option<&str>,
|
||||
parent_set: &Set,
|
||||
configuration: ConfigurationFile,
|
||||
) -> String {
|
||||
match configuration {
|
||||
ConfigurationFile::PyprojectToml => format!("[tool.ruff{fmt}]"),
|
||||
ConfigurationFile::PyprojectToml => {
|
||||
let mut header = if let Some(set_name) = parent_set.name() {
|
||||
if set_name == "format" {
|
||||
String::from("tool.ruff.format")
|
||||
} else {
|
||||
format!("tool.ruff.lint.{set_name}")
|
||||
}
|
||||
} else {
|
||||
"tool.ruff".to_string()
|
||||
};
|
||||
if let Some(scope) = scope {
|
||||
if !header.is_empty() {
|
||||
header.push('.');
|
||||
}
|
||||
header.push_str(scope);
|
||||
}
|
||||
format!("[{header}]")
|
||||
}
|
||||
ConfigurationFile::RuffToml => {
|
||||
if fmt.is_empty() {
|
||||
let mut header = if let Some(set_name) = parent_set.name() {
|
||||
if set_name == "format" {
|
||||
String::from("format")
|
||||
} else {
|
||||
format!("lint.{set_name}")
|
||||
}
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
if let Some(scope) = scope {
|
||||
if !header.is_empty() {
|
||||
header.push('.');
|
||||
}
|
||||
header.push_str(scope);
|
||||
}
|
||||
if header.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!("[{}]", fmt.strip_prefix('.').unwrap())
|
||||
format!("[{header}]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::edit::Edit;
|
||||
pub enum Applicability {
|
||||
/// The fix is unsafe and should only be displayed for manual application by the user.
|
||||
/// The fix is likely to be incorrect or the resulting code may have invalid syntax.
|
||||
Display,
|
||||
DisplayOnly,
|
||||
|
||||
/// The fix is unsafe and should only be applied with user opt-in.
|
||||
/// The fix may be what the user intended, but it is uncertain; the resulting code will have valid syntax.
|
||||
@@ -87,22 +87,22 @@ impl Fix {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`Fix`] that should only [display](Applicability::Display) and not apply from an [`Edit`] element .
|
||||
pub fn display_edit(edit: Edit) -> Self {
|
||||
/// Create a new [`Fix`] that should only [display](Applicability::DisplayOnly) and not apply from an [`Edit`] element .
|
||||
pub fn display_only_edit(edit: Edit) -> Self {
|
||||
Self {
|
||||
edits: vec![edit],
|
||||
applicability: Applicability::Display,
|
||||
applicability: Applicability::DisplayOnly,
|
||||
isolation_level: IsolationLevel::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`Fix`] that should only [display](Applicability::Display) and not apply from multiple [`Edit`] elements.
|
||||
pub fn display_edits(edit: Edit, rest: impl IntoIterator<Item = Edit>) -> Self {
|
||||
/// Create a new [`Fix`] that should only [display](Applicability::DisplayOnly) and not apply from multiple [`Edit`] elements.
|
||||
pub fn display_only_edits(edit: Edit, rest: impl IntoIterator<Item = Edit>) -> Self {
|
||||
let mut edits: Vec<Edit> = std::iter::once(edit).chain(rest).collect();
|
||||
edits.sort_by_key(|edit| (edit.start(), edit.end()));
|
||||
Self {
|
||||
edits,
|
||||
applicability: Applicability::Display,
|
||||
applicability: Applicability::DisplayOnly,
|
||||
isolation_level: IsolationLevel::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,3 +29,6 @@ insta = { workspace = true }
|
||||
[features]
|
||||
serde = ["dep:serde", "ruff_text_size/serde"]
|
||||
schemars = ["dep:schemars", "ruff_text_size/schemars"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1711,14 +1711,14 @@ mod tests {
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
r#"a
|
||||
"a
|
||||
b
|
||||
c
|
||||
d
|
||||
d
|
||||
c
|
||||
b
|
||||
a"#,
|
||||
a",
|
||||
formatted.as_code()
|
||||
);
|
||||
}
|
||||
@@ -2047,10 +2047,10 @@ two lines`,
|
||||
|
||||
assert_eq!(
|
||||
printed.as_code(),
|
||||
r#"Group with id-2
|
||||
"Group with id-2
|
||||
Group with id-1 does not fit on the line because it exceeds the line width of 80 characters by
|
||||
Group 2 fits
|
||||
Group 1 breaks"#
|
||||
Group 1 breaks"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,3 +17,6 @@ ruff_macros = { path = "../ruff_macros" }
|
||||
|
||||
[dev-dependencies]
|
||||
static_assertions = "1.1.0"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_linter"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
@@ -30,7 +30,7 @@ ruff_source_file = { path = "../ruff_source_file", features = ["serde"] }
|
||||
ruff_text_size = { path = "../ruff_text_size" }
|
||||
|
||||
aho-corasick = { version = "1.1.2" }
|
||||
annotate-snippets = { version = "0.9.1", features = ["color"] }
|
||||
annotate-snippets = { version = "0.9.2", features = ["color"] }
|
||||
anyhow = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
@@ -53,8 +53,8 @@ path-absolutize = { workspace = true, features = [
|
||||
] }
|
||||
pathdiff = { version = "0.2.1" }
|
||||
pep440_rs = { version = "0.3.12", features = ["serde"] }
|
||||
pyproject-toml = { version = "0.8.0" }
|
||||
quick-junit = { version = "0.3.2" }
|
||||
pyproject-toml = { version = "0.8.1" }
|
||||
quick-junit = { version = "0.3.5" }
|
||||
regex = { workspace = true }
|
||||
result-like = { version = "0.4.6" }
|
||||
rustc-hash = { workspace = true }
|
||||
@@ -86,3 +86,6 @@ default = []
|
||||
schemars = ["dep:schemars"]
|
||||
# Enables the UnreachableCode rule
|
||||
unreachable-code = []
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# fixtures
|
||||
|
||||
Fixture files used for snapshot testing.
|
||||
32
crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py
vendored
Normal file
32
crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
def func():
|
||||
return 1
|
||||
|
||||
|
||||
def func():
|
||||
return 1.5
|
||||
|
||||
|
||||
def func(x: int):
|
||||
if x > 0:
|
||||
return 1
|
||||
else:
|
||||
return 1.5
|
||||
|
||||
|
||||
def func():
|
||||
return True
|
||||
|
||||
|
||||
def func(x: int):
|
||||
if x > 0:
|
||||
return None
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
def func(x: int):
|
||||
return 1 or 2.5 if x > 0 else 1.5 or "str"
|
||||
|
||||
|
||||
def func(x: int):
|
||||
return 1 + 2.5 if x > 0 else 1.5 or "str"
|
||||
65
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S202.py
vendored
Normal file
65
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S202.py
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
import sys
|
||||
import tarfile
|
||||
import tempfile
|
||||
|
||||
|
||||
def unsafe_archive_handler(filename):
|
||||
tar = tarfile.open(filename)
|
||||
tar.extractall(path=tempfile.mkdtemp())
|
||||
tar.close()
|
||||
|
||||
|
||||
def managed_members_archive_handler(filename):
|
||||
tar = tarfile.open(filename)
|
||||
tar.extractall(path=tempfile.mkdtemp(), members=members_filter(tar))
|
||||
tar.close()
|
||||
|
||||
|
||||
def list_members_archive_handler(filename):
|
||||
tar = tarfile.open(filename)
|
||||
tar.extractall(path=tempfile.mkdtemp(), members=[])
|
||||
tar.close()
|
||||
|
||||
|
||||
def provided_members_archive_handler(filename):
|
||||
tar = tarfile.open(filename)
|
||||
tarfile.extractall(path=tempfile.mkdtemp(), members=tar)
|
||||
tar.close()
|
||||
|
||||
|
||||
def filter_data(filename):
|
||||
tar = tarfile.open(filename)
|
||||
tarfile.extractall(path=tempfile.mkdtemp(), filter="data")
|
||||
tar.close()
|
||||
|
||||
|
||||
def filter_fully_trusted(filename):
|
||||
tar = tarfile.open(filename)
|
||||
tarfile.extractall(path=tempfile.mkdtemp(), filter="fully_trusted")
|
||||
tar.close()
|
||||
|
||||
|
||||
def filter_tar(filename):
|
||||
tar = tarfile.open(filename)
|
||||
tarfile.extractall(path=tempfile.mkdtemp(), filter="tar")
|
||||
tar.close()
|
||||
|
||||
|
||||
def members_filter(tarfile):
|
||||
result = []
|
||||
for member in tarfile.getmembers():
|
||||
if '../' in member.name:
|
||||
print('Member name container directory traversal sequence')
|
||||
continue
|
||||
elif (member.issym() or member.islnk()) and ('../' in member.linkname):
|
||||
print('Symlink to external resource')
|
||||
continue
|
||||
result.append(member)
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
filename = sys.argv[1]
|
||||
unsafe_archive_handler(filename)
|
||||
managed_members_archive_handler(filename)
|
||||
13
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S611.py
vendored
Normal file
13
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S611.py
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
from django.db.models.expressions import RawSQL
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
User.objects.annotate(val=RawSQL('secure', []))
|
||||
User.objects.annotate(val=RawSQL('%secure' % 'nos', []))
|
||||
User.objects.annotate(val=RawSQL('{}secure'.format('no'), []))
|
||||
raw = '"username") AS "val" FROM "auth_user" WHERE "username"="admin" --'
|
||||
User.objects.annotate(val=RawSQL(raw, []))
|
||||
raw = '"username") AS "val" FROM "auth_user"' \
|
||||
' WHERE "username"="admin" OR 1=%s --'
|
||||
User.objects.annotate(val=RawSQL(raw, [0]))
|
||||
User.objects.annotate(val=RawSQL(sql='{}secure'.format('no'), params=[]))
|
||||
User.objects.annotate(val=RawSQL(params=[], sql='{}secure'.format('no')))
|
||||
9
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S702.py
vendored
Normal file
9
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S702.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
from mako.template import Template
|
||||
from mako import template
|
||||
import mako
|
||||
|
||||
|
||||
Template("hello")
|
||||
|
||||
mako.template.Template("hern")
|
||||
template.Template("hern")
|
||||
@@ -91,3 +91,18 @@ class Registry:
|
||||
|
||||
def foo(self) -> None:
|
||||
object.__setattr__(self, "flag", True)
|
||||
|
||||
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
def func(x: Union[list, Optional[int | str | float | bool]]):
|
||||
pass
|
||||
|
||||
|
||||
def func(x: bool | str):
|
||||
pass
|
||||
|
||||
|
||||
def func(x: int | str):
|
||||
pass
|
||||
|
||||
149
crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B015.ipynb
vendored
Normal file
149
crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B015.ipynb
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "33faf7ad-a3fd-4ac4-a0c3-52e507ed49df",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"x = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "481fb4bf-c1b9-47da-927f-3cfdfe4b49ec",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Simple case\n",
|
||||
"x == 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "2f0c65a5-0a0e-4080-afce-5a8ed0d706df",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Only skip the last expression\n",
|
||||
"x == 1 # B018\n",
|
||||
"x == 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "5a3fd75d-26d9-44f7-b013-1684aabfd0ae",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Nested expressions isn't relevant\n",
|
||||
"if True:\n",
|
||||
" x == 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "e00e1afa-b76c-4774-be2a-7223641579e4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Semicolons shouldn't affect the output\n",
|
||||
"x == 1;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "05eab5b9-e2ba-4954-8ef3-b035a79573fe",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Semicolons with multiple expressions\n",
|
||||
"x == 1; x == 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "9cbbddc5-83fc-4fdb-81ab-53a3912ae898",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Comments, newlines and whitespace\n",
|
||||
"x == 1 # comment\n",
|
||||
"\n",
|
||||
"# another comment"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python (ruff-playground)",
|
||||
"language": "python",
|
||||
"name": "ruff-playground"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
149
crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B018.ipynb
vendored
Normal file
149
crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B018.ipynb
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "33faf7ad-a3fd-4ac4-a0c3-52e507ed49df",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"x = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "481fb4bf-c1b9-47da-927f-3cfdfe4b49ec",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Simple case\n",
|
||||
"x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "2f0c65a5-0a0e-4080-afce-5a8ed0d706df",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Only skip the last expression\n",
|
||||
"x # B018\n",
|
||||
"x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "5a3fd75d-26d9-44f7-b013-1684aabfd0ae",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Nested expressions isn't relevant\n",
|
||||
"if True:\n",
|
||||
" x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "e00e1afa-b76c-4774-be2a-7223641579e4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Semicolons shouldn't affect the output\n",
|
||||
"x;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "05eab5b9-e2ba-4954-8ef3-b035a79573fe",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Semicolons with multiple expressions\n",
|
||||
"x; x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "9cbbddc5-83fc-4fdb-81ab-53a3912ae898",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Comments, newlines and whitespace\n",
|
||||
"x # comment\n",
|
||||
"\n",
|
||||
"# another comment"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python (ruff-playground)",
|
||||
"language": "python",
|
||||
"name": "ruff-playground"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -639,3 +639,18 @@ foo = namedtuple(
|
||||
:20
|
||||
],
|
||||
)
|
||||
|
||||
# F-strings
|
||||
kwargs.pop("remove", f"this {trailing_comma}",)
|
||||
|
||||
raise Exception(
|
||||
"first", extra=f"Add trailing comma here ->"
|
||||
)
|
||||
|
||||
assert False, f"<- This is not a trailing comma"
|
||||
|
||||
f"""This is a test. {
|
||||
"Another sentence."
|
||||
if True else
|
||||
"Don't add a trailing comma here ->"
|
||||
}"""
|
||||
|
||||
@@ -58,3 +58,33 @@ def f_fix_indentation_check(foo):
|
||||
# Report these, but don't fix them
|
||||
if foo: raise RuntimeError("This is an example exception")
|
||||
if foo: x = 1; raise RuntimeError("This is an example exception")
|
||||
|
||||
|
||||
def f_triple_quoted_string():
|
||||
raise RuntimeError(f"""This is an {"example"} exception""")
|
||||
|
||||
|
||||
def f_multi_line_string():
|
||||
raise RuntimeError(
|
||||
"first"
|
||||
"second"
|
||||
)
|
||||
|
||||
|
||||
def f_multi_line_string2():
|
||||
raise RuntimeError(
|
||||
"This is an {example} exception".format(
|
||||
example="example"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def f_multi_line_string2():
|
||||
raise RuntimeError(
|
||||
(
|
||||
"This is an "
|
||||
"{example} exception"
|
||||
).format(
|
||||
example="example"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -148,3 +148,62 @@ for i in range(10):
|
||||
for i in range(10):
|
||||
pass # comment
|
||||
pass
|
||||
|
||||
|
||||
def foo():
|
||||
print("foo")
|
||||
...
|
||||
|
||||
|
||||
def foo():
|
||||
"""A docstring."""
|
||||
print("foo")
|
||||
...
|
||||
|
||||
|
||||
for i in range(10):
|
||||
...
|
||||
...
|
||||
|
||||
for i in range(10):
|
||||
...
|
||||
|
||||
...
|
||||
|
||||
for i in range(10):
|
||||
... # comment
|
||||
...
|
||||
|
||||
for i in range(10):
|
||||
...
|
||||
pass
|
||||
|
||||
from typing import Protocol
|
||||
|
||||
|
||||
class Repro(Protocol):
|
||||
def func(self) -> str:
|
||||
"""Docstring"""
|
||||
...
|
||||
|
||||
def impl(self) -> str:
|
||||
"""Docstring"""
|
||||
return self.func()
|
||||
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class Repro:
|
||||
@abc.abstractmethod
|
||||
def func(self) -> str:
|
||||
"""Docstring"""
|
||||
...
|
||||
|
||||
def impl(self) -> str:
|
||||
"""Docstring"""
|
||||
return self.func()
|
||||
|
||||
def stub(self) -> str:
|
||||
"""Docstring"""
|
||||
...
|
||||
|
||||
@@ -38,3 +38,15 @@ class User:
|
||||
foo: bool = BooleanField()
|
||||
# ...
|
||||
bar = StringField() # PIE794
|
||||
|
||||
|
||||
class Person:
|
||||
name = "Foo"
|
||||
name = name + " Bar"
|
||||
name = "Bar" # PIE794
|
||||
|
||||
|
||||
class Person:
|
||||
name: str = "Foo"
|
||||
name: str = name + " Bar"
|
||||
name: str = "Bar" # PIE794
|
||||
|
||||
@@ -64,3 +64,9 @@ class FakeEnum10(enum.Enum):
|
||||
A = enum.auto()
|
||||
B = enum.auto()
|
||||
C = enum.auto()
|
||||
|
||||
|
||||
class FakeEnum10(enum.Enum):
|
||||
A = ...
|
||||
B = ... # PIE796
|
||||
C = ... # PIE796
|
||||
|
||||
7
crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE796.pyi
vendored
Normal file
7
crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE796.pyi
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import enum
|
||||
|
||||
|
||||
class FakeEnum1(enum.Enum):
|
||||
A = ...
|
||||
B = ...
|
||||
C = ...
|
||||
@@ -1,9 +1,21 @@
|
||||
{"foo": 1, **{"bar": 1}} # PIE800
|
||||
|
||||
{**{"bar": 10}, "a": "b"} # PIE800
|
||||
|
||||
foo({**foo, **{"bar": True}}) # PIE800
|
||||
|
||||
{**foo, **{"bar": 10}} # PIE800
|
||||
|
||||
{ # PIE800
|
||||
"a": "b",
|
||||
# Preserve
|
||||
**{
|
||||
# all
|
||||
"bar": 10, # the
|
||||
# comments
|
||||
},
|
||||
}
|
||||
|
||||
{**foo, **buzz, **{bar: 10}} # PIE800
|
||||
|
||||
{**foo, "bar": True } # OK
|
||||
|
||||
@@ -1,27 +1,37 @@
|
||||
@dataclass
|
||||
class Foo:
|
||||
foo: List[str] = field(default_factory=lambda: []) # PIE807
|
||||
bar: Dict[str, int] = field(default_factory=lambda: {}) # PIE807
|
||||
|
||||
|
||||
class FooTable(BaseTable):
|
||||
bar = fields.ListField(default=lambda: []) # PIE807
|
||||
foo = fields.ListField(default=lambda: []) # PIE807
|
||||
bar = fields.ListField(default=lambda: {}) # PIE807
|
||||
|
||||
|
||||
class FooTable(BaseTable):
|
||||
bar = fields.ListField(lambda: []) # PIE807
|
||||
foo = fields.ListField(lambda: []) # PIE807
|
||||
bar = fields.ListField(default=lambda: {}) # PIE807
|
||||
|
||||
|
||||
@dataclass
|
||||
class Foo:
|
||||
foo: List[str] = field(default_factory=list)
|
||||
bar: Dict[str, int] = field(default_factory=dict)
|
||||
|
||||
|
||||
class FooTable(BaseTable):
|
||||
bar = fields.ListField(list)
|
||||
foo = fields.ListField(list)
|
||||
bar = fields.ListField(dict)
|
||||
|
||||
|
||||
lambda *args, **kwargs: []
|
||||
lambda *args, **kwargs: {}
|
||||
|
||||
lambda *args: []
|
||||
lambda *args: {}
|
||||
|
||||
lambda **kwargs: []
|
||||
lambda **kwargs: {}
|
||||
|
||||
lambda: {**unwrap}
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
import abc
|
||||
import builtins
|
||||
import collections.abc
|
||||
import enum
|
||||
import typing
|
||||
from abc import abstractmethod
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from collections.abc import AsyncIterable, AsyncIterator, Iterable, Iterator
|
||||
from enum import EnumMeta
|
||||
from typing import Any, overload
|
||||
|
||||
import typing_extensions
|
||||
@@ -199,6 +201,31 @@ class AsyncIteratorReturningAsyncIterable:
|
||||
... # Y045 "__aiter__" methods should return an AsyncIterator, not an AsyncIterable
|
||||
|
||||
|
||||
class MetaclassInWhichSelfCannotBeUsed(type):
|
||||
def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed: ...
|
||||
def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed: ...
|
||||
async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed: ...
|
||||
def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed) -> MetaclassInWhichSelfCannotBeUsed: ...
|
||||
|
||||
class MetaclassInWhichSelfCannotBeUsed2(EnumMeta):
|
||||
def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed2: ...
|
||||
def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed2: ...
|
||||
async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed2: ...
|
||||
def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed2) -> MetaclassInWhichSelfCannotBeUsed2: ...
|
||||
|
||||
class MetaclassInWhichSelfCannotBeUsed3(enum.EnumType):
|
||||
def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed3: ...
|
||||
def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed3: ...
|
||||
async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed3: ...
|
||||
def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed3) -> MetaclassInWhichSelfCannotBeUsed3: ...
|
||||
|
||||
class MetaclassInWhichSelfCannotBeUsed4(ABCMeta):
|
||||
def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed4: ...
|
||||
def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed4: ...
|
||||
async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed4: ...
|
||||
def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed4) -> MetaclassInWhichSelfCannotBeUsed4: ...
|
||||
|
||||
|
||||
class Abstract(Iterator[str]):
|
||||
@abstractmethod
|
||||
def __iter__(self) -> Iterator[str]:
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
import abc
|
||||
import builtins
|
||||
import collections.abc
|
||||
import enum
|
||||
import typing
|
||||
from abc import abstractmethod
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from collections.abc import AsyncIterable, AsyncIterator, Iterable, Iterator
|
||||
from enum import EnumMeta
|
||||
from typing import Any, overload
|
||||
|
||||
import typing_extensions
|
||||
@@ -152,6 +154,30 @@ class AsyncIteratorReturningAsyncIterable:
|
||||
str
|
||||
]: ... # Y045 "__aiter__" methods should return an AsyncIterator, not an AsyncIterable
|
||||
|
||||
class MetaclassInWhichSelfCannotBeUsed(type):
|
||||
def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed: ...
|
||||
def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed: ...
|
||||
async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed: ...
|
||||
def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed) -> MetaclassInWhichSelfCannotBeUsed: ...
|
||||
|
||||
class MetaclassInWhichSelfCannotBeUsed2(EnumMeta):
|
||||
def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed2: ...
|
||||
def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed2: ...
|
||||
async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed2: ...
|
||||
def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed2) -> MetaclassInWhichSelfCannotBeUsed2: ...
|
||||
|
||||
class MetaclassInWhichSelfCannotBeUsed3(enum.EnumType):
|
||||
def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed3: ...
|
||||
def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed3: ...
|
||||
async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed3: ...
|
||||
def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed3) -> MetaclassInWhichSelfCannotBeUsed3: ...
|
||||
|
||||
class MetaclassInWhichSelfCannotBeUsed4(ABCMeta):
|
||||
def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed4: ...
|
||||
def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed4: ...
|
||||
async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed4: ...
|
||||
def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed4) -> MetaclassInWhichSelfCannotBeUsed4: ...
|
||||
|
||||
class Abstract(Iterator[str]):
|
||||
@abstractmethod
|
||||
def __iter__(self) -> Iterator[str]: ...
|
||||
|
||||
@@ -91,3 +91,17 @@ field27 = list[str]
|
||||
field28 = builtins.str
|
||||
field29 = str
|
||||
field30 = str | bytes | None
|
||||
|
||||
# We shouldn't emit Y052 for `enum` subclasses.
|
||||
from enum import Enum
|
||||
|
||||
class Foo(Enum):
|
||||
FOO = 0
|
||||
BAR = 1
|
||||
|
||||
class Bar(Foo):
|
||||
BAZ = 2
|
||||
BOP = 3
|
||||
|
||||
class Bop:
|
||||
WIZ = 4
|
||||
|
||||
@@ -98,3 +98,17 @@ field27 = list[str]
|
||||
field28 = builtins.str
|
||||
field29 = str
|
||||
field30 = str | bytes | None
|
||||
|
||||
# We shouldn't emit Y052 for `enum` subclasses.
|
||||
from enum import Enum
|
||||
|
||||
class Foo(Enum):
|
||||
FOO = 0
|
||||
BAR = 1
|
||||
|
||||
class Bar(Foo):
|
||||
BAZ = 2
|
||||
BOP = 3
|
||||
|
||||
class Bop:
|
||||
WIZ = 4
|
||||
|
||||
45
crates/ruff_linter/resources/test/fixtures/flake8_quotes/doubles_escaped_unnecessary.py
vendored
Normal file
45
crates/ruff_linter/resources/test/fixtures/flake8_quotes/doubles_escaped_unnecessary.py
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
this_should_raise_Q004 = 'This is a \"string\"'
|
||||
this_should_raise_Q004 = 'This is \\ a \\\"string\"'
|
||||
this_is_fine = '"This" is a \"string\"'
|
||||
this_is_fine = "This is a 'string'"
|
||||
this_is_fine = "\"This\" is a 'string'"
|
||||
this_is_fine = r'This is a \"string\"'
|
||||
this_is_fine = R'This is a \"string\"'
|
||||
this_should_raise_Q004 = (
|
||||
'This is a'
|
||||
'\"string\"'
|
||||
)
|
||||
|
||||
# Same as above, but with f-strings
|
||||
f'This is a \"string\"' # Q004
|
||||
f'This is \\ a \\\"string\"' # Q004
|
||||
f'"This" is a \"string\"'
|
||||
f"This is a 'string'"
|
||||
f"\"This\" is a 'string'"
|
||||
fr'This is a \"string\"'
|
||||
fR'This is a \"string\"'
|
||||
this_should_raise_Q004 = (
|
||||
f'This is a'
|
||||
f'\"string\"' # Q004
|
||||
)
|
||||
|
||||
# Nested f-strings (Python 3.12+)
|
||||
#
|
||||
# The first one is interesting because the fix for it is valid pre 3.12:
|
||||
#
|
||||
# f"'foo' {'nested'}"
|
||||
#
|
||||
# but as the actual string itself is invalid pre 3.12, we don't catch it.
|
||||
f'\"foo\" {'nested'}' # Q004
|
||||
f'\"foo\" {f'nested'}' # Q004
|
||||
f'\"foo\" {f'\"nested\"'} \"\"' # Q004
|
||||
|
||||
f'normal {f'nested'} normal'
|
||||
f'\"normal\" {f'nested'} normal' # Q004
|
||||
f'\"normal\" {f'nested'} "double quotes"'
|
||||
f'\"normal\" {f'\"nested\" {'other'} normal'} "double quotes"' # Q004
|
||||
f'\"normal\" {f'\"nested\" {'other'} "double quotes"'} normal' # Q004
|
||||
|
||||
# Make sure we do not unescape quotes
|
||||
this_is_fine = 'This is an \\"escaped\\" quote'
|
||||
this_should_raise_Q004 = 'This is an \\\"escaped\\\" quote with an extra backslash'
|
||||
43
crates/ruff_linter/resources/test/fixtures/flake8_quotes/singles_escaped_unnecessary.py
vendored
Normal file
43
crates/ruff_linter/resources/test/fixtures/flake8_quotes/singles_escaped_unnecessary.py
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
this_should_raise_Q004 = "This is a \'string\'"
|
||||
this_should_raise_Q004 = "'This' is a \'string\'"
|
||||
this_is_fine = 'This is a "string"'
|
||||
this_is_fine = '\'This\' is a "string"'
|
||||
this_is_fine = r"This is a \'string\'"
|
||||
this_is_fine = R"This is a \'string\'"
|
||||
this_should_raise_Q004 = (
|
||||
"This is a"
|
||||
"\'string\'"
|
||||
)
|
||||
|
||||
# Same as above, but with f-strings
|
||||
f"This is a \'string\'" # Q004
|
||||
f"'This' is a \'string\'" # Q004
|
||||
f'This is a "string"'
|
||||
f'\'This\' is a "string"'
|
||||
fr"This is a \'string\'"
|
||||
fR"This is a \'string\'"
|
||||
this_should_raise_Q004 = (
|
||||
f"This is a"
|
||||
f"\'string\'" # Q004
|
||||
)
|
||||
|
||||
# Nested f-strings (Python 3.12+)
|
||||
#
|
||||
# The first one is interesting because the fix for it is valid pre 3.12:
|
||||
#
|
||||
# f'"foo" {"nested"}'
|
||||
#
|
||||
# but as the actual string itself is invalid pre 3.12, we don't catch it.
|
||||
f"\'foo\' {"foo"}" # Q004
|
||||
f"\'foo\' {f"foo"}" # Q004
|
||||
f"\'foo\' {f"\'foo\'"} \'\'" # Q004
|
||||
|
||||
f"normal {f"nested"} normal"
|
||||
f"\'normal\' {f"nested"} normal" # Q004
|
||||
f"\'normal\' {f"nested"} 'single quotes'"
|
||||
f"\'normal\' {f"\'nested\' {"other"} normal"} 'single quotes'" # Q004
|
||||
f"\'normal\' {f"\'nested\' {"other"} 'single quotes'"} normal" # Q004
|
||||
|
||||
# Make sure we do not unescape quotes
|
||||
this_is_fine = "This is an \\'escaped\\' quote"
|
||||
this_should_raise_Q004 = "This is an \\\'escaped\\\' quote with an extra backslash"
|
||||
@@ -134,3 +134,32 @@ with A() as a:
|
||||
f" something { my_dict["key"] } something else "
|
||||
|
||||
f"foo {f"bar {x}"} baz"
|
||||
|
||||
# Allow cascading for some statements.
|
||||
import anyio
|
||||
import asyncio
|
||||
import trio
|
||||
|
||||
async with asyncio.timeout(1):
|
||||
async with A() as a:
|
||||
pass
|
||||
|
||||
async with A():
|
||||
async with asyncio.timeout(1):
|
||||
pass
|
||||
|
||||
async with asyncio.timeout(1):
|
||||
async with asyncio.timeout_at(1):
|
||||
async with anyio.CancelScope():
|
||||
async with anyio.fail_after(1):
|
||||
async with anyio.move_on_after(1):
|
||||
async with trio.fail_after(1):
|
||||
async with trio.fail_at(1):
|
||||
async with trio.move_on_after(1):
|
||||
async with trio.move_on_at(1):
|
||||
pass
|
||||
|
||||
# Do not supress combination, if a context manager is already combined with another.
|
||||
async with asyncio.timeout(1), A():
|
||||
async with B():
|
||||
pass
|
||||
|
||||
@@ -25,3 +25,11 @@ a = {}.get(key, None)
|
||||
|
||||
# SIM910
|
||||
({}).get(key, None)
|
||||
|
||||
# SIM910
|
||||
ages = {"Tom": 23, "Maria": 23, "Dog": 11}
|
||||
age = ages.get("Cat", None)
|
||||
|
||||
# OK
|
||||
ages = ["Tom", "Maria", "Dog"]
|
||||
age = ages.get("Cat", None)
|
||||
|
||||
13
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO109.py
vendored
Normal file
13
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO109.py
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import trio
|
||||
|
||||
|
||||
async def func():
|
||||
...
|
||||
|
||||
|
||||
async def func(timeout):
|
||||
...
|
||||
|
||||
|
||||
async def func(timeout=10):
|
||||
...
|
||||
16
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO110.py
vendored
Normal file
16
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO110.py
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import trio
|
||||
|
||||
|
||||
async def func():
|
||||
while True:
|
||||
await trio.sleep(10)
|
||||
|
||||
|
||||
async def func():
|
||||
while True:
|
||||
await trio.sleep_until(10)
|
||||
|
||||
|
||||
async def func():
|
||||
while True:
|
||||
trio.sleep(10)
|
||||
@@ -1,8 +1,7 @@
|
||||
import trio
|
||||
from trio import sleep
|
||||
|
||||
|
||||
async def func():
|
||||
import trio
|
||||
from trio import sleep
|
||||
|
||||
await trio.sleep(0) # TRIO115
|
||||
await trio.sleep(1) # OK
|
||||
await trio.sleep(0, 1) # OK
|
||||
@@ -21,8 +20,11 @@ async def func():
|
||||
trio.sleep(bar)
|
||||
|
||||
|
||||
trio.sleep(0) # TRIO115
|
||||
|
||||
|
||||
def func():
|
||||
trio.run(trio.sleep(0)) # TRIO115
|
||||
|
||||
|
||||
from trio import Event, sleep
|
||||
|
||||
def func():
|
||||
sleep(0) # TRIO115
|
||||
|
||||
@@ -172,3 +172,14 @@ def f():
|
||||
from module import Member
|
||||
|
||||
x: Member = 1
|
||||
|
||||
|
||||
def f():
|
||||
from typing_extensions import TYPE_CHECKING
|
||||
|
||||
from pandas import y
|
||||
|
||||
if TYPE_CHECKING:
|
||||
_type = x
|
||||
elif True:
|
||||
_type = y
|
||||
|
||||
10
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TCH004_16.py
vendored
Normal file
10
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TCH004_16.py
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing_extensions import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pandas import DataFrame
|
||||
|
||||
|
||||
def example() -> DataFrame:
|
||||
pass
|
||||
10
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TCH004_17.py
vendored
Normal file
10
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TCH004_17.py
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing_extensions import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pandas import DataFrame
|
||||
|
||||
|
||||
def example() -> DataFrame:
|
||||
x = DataFrame()
|
||||
@@ -37,3 +37,9 @@ if False:
|
||||
|
||||
if 0:
|
||||
x: List
|
||||
|
||||
|
||||
from typing_extensions import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass # TCH005
|
||||
|
||||
0
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/__init__.py
vendored
Normal file
0
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/__init__.py
vendored
Normal file
11
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/direct.py
vendored
Normal file
11
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/direct.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
class MyBaseClass:
|
||||
pass
|
||||
|
||||
|
||||
class Foo(MyBaseClass):
|
||||
foo: Sequence
|
||||
9
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/import.py
vendored
Normal file
9
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/import.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
from module.direct import MyBaseClass
|
||||
|
||||
|
||||
class Foo(MyBaseClass):
|
||||
foo: Sequence
|
||||
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/undefined.py
vendored
Normal file
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/undefined.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
class Foo(MyBaseClass):
|
||||
foo: Sequence
|
||||
@@ -0,0 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pandas import DataFrame
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Parent(BaseModel):
|
||||
...
|
||||
|
||||
|
||||
class Child(Parent):
|
||||
baz: DataFrame
|
||||
9
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/typing_modules_1.py
vendored
Normal file
9
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/typing_modules_1.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
def func():
|
||||
from pandas import DataFrame
|
||||
|
||||
df: DataFrame
|
||||
9
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/typing_modules_2.py
vendored
Normal file
9
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/typing_modules_2.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import typing_extensions
|
||||
|
||||
|
||||
def func():
|
||||
from pandas import DataFrame
|
||||
|
||||
df: DataFrame
|
||||
5
crates/ruff_linter/resources/test/fixtures/isort/force_sort_within_sections_with_as_names.py
vendored
Normal file
5
crates/ruff_linter/resources/test/fixtures/isort/force_sort_within_sections_with_as_names.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import encodings
|
||||
from datetime import timezone as tz
|
||||
from datetime import timedelta
|
||||
import datetime as dt
|
||||
import datetime
|
||||
5
crates/ruff_linter/resources/test/fixtures/isort/from_first.py
vendored
Normal file
5
crates/ruff_linter/resources/test/fixtures/isort/from_first.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
from __future__ import blah
|
||||
|
||||
from os import path
|
||||
|
||||
import os
|
||||
11
crates/ruff_linter/resources/test/fixtures/isort/main_first_party.py
vendored
Normal file
11
crates/ruff_linter/resources/test/fixtures/isort/main_first_party.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import os
|
||||
|
||||
import __main__
|
||||
import third_party
|
||||
|
||||
import first_party
|
||||
|
||||
os.a
|
||||
third_party.a
|
||||
__main__.a
|
||||
first_party.a
|
||||
8
crates/ruff_linter/resources/test/fixtures/isort/no_sections.py
vendored
Normal file
8
crates/ruff_linter/resources/test/fixtures/isort/no_sections.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import django.settings
|
||||
import os
|
||||
import pytz
|
||||
import sys
|
||||
from . import local
|
||||
from library import foo
|
||||
@@ -63,3 +63,33 @@ class PosOnlyClass:
|
||||
|
||||
def bad_method_pos_only(this, blah, /, self, something: str):
|
||||
pass
|
||||
|
||||
|
||||
class ModelClass:
|
||||
@hybrid_property
|
||||
def bad(cls):
|
||||
pass
|
||||
|
||||
@bad.expression
|
||||
def bad(self):
|
||||
pass
|
||||
|
||||
@bad.wtf
|
||||
def bad(cls):
|
||||
pass
|
||||
|
||||
@hybrid_property
|
||||
def good(self):
|
||||
pass
|
||||
|
||||
@good.expression
|
||||
def good(cls):
|
||||
pass
|
||||
|
||||
@good.wtf
|
||||
def good(self):
|
||||
pass
|
||||
|
||||
@foobar.thisisstatic
|
||||
def badstatic(foo):
|
||||
pass
|
||||
|
||||
@@ -25,6 +25,8 @@ def assign():
|
||||
|
||||
IntOrStr: TypeAlias = int | str
|
||||
|
||||
type MyInt = int
|
||||
|
||||
|
||||
def aug_assign(rank, world_size):
|
||||
global CURRENT_PORT
|
||||
|
||||
@@ -50,3 +50,16 @@ import itertools
|
||||
|
||||
for i in itertools.product(foo_int): # Ok
|
||||
pass
|
||||
|
||||
for i in list(foo_list): # Ok
|
||||
foo_list.append(i + 1)
|
||||
|
||||
for i in list(foo_list): # PERF101
|
||||
# Make sure we match the correct list
|
||||
other_list.append(i + 1)
|
||||
|
||||
for i in list(foo_tuple): # Ok
|
||||
foo_tuple.append(i + 1)
|
||||
|
||||
for i in list(foo_set): # Ok
|
||||
foo_set.append(i + 1)
|
||||
|
||||
@@ -89,3 +89,61 @@ x = [ #
|
||||
f"{ {'a': 1} }"
|
||||
f"{[ { {'a': 1} } ]}"
|
||||
f"normal { {f"{ { [1, 2] } }" } } normal"
|
||||
|
||||
#: Okay
|
||||
ham[lower + offset : upper + offset]
|
||||
|
||||
#: Okay
|
||||
ham[(lower + offset) : upper + offset]
|
||||
|
||||
#: E203:1:19
|
||||
ham{lower + offset : upper + offset}
|
||||
|
||||
#: E203:1:19
|
||||
ham[lower + offset : upper + offset]
|
||||
|
||||
#: Okay
|
||||
release_lines = history_file_lines[history_file_lines.index('## Unreleased') + 1: -1]
|
||||
|
||||
#: Okay
|
||||
release_lines = history_file_lines[history_file_lines.index('## Unreleased') + 1 : -1]
|
||||
|
||||
#: Okay
|
||||
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
|
||||
ham[lower:upper], ham[lower:upper:], ham[lower::step]
|
||||
ham[lower+offset : upper+offset]
|
||||
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
|
||||
ham[lower + offset : upper + offset]
|
||||
|
||||
#: E201:1:5
|
||||
ham[ : upper]
|
||||
|
||||
#: Okay
|
||||
ham[lower + offset :: upper + offset]
|
||||
|
||||
#: Okay
|
||||
ham[(lower + offset) :: upper + offset]
|
||||
|
||||
#: Okay
|
||||
ham[lower + offset::upper + offset]
|
||||
|
||||
#: E203:1:21
|
||||
ham[lower + offset : : upper + offset]
|
||||
|
||||
#: E203:1:20
|
||||
ham[lower + offset: :upper + offset]
|
||||
|
||||
#: E203:1:20
|
||||
ham[{lower + offset : upper + offset} : upper + offset]
|
||||
|
||||
#: Okay
|
||||
ham[upper:]
|
||||
|
||||
#: Okay
|
||||
ham[upper :]
|
||||
|
||||
#: E202:1:12
|
||||
ham[upper : ]
|
||||
|
||||
#: E203:1:10
|
||||
ham[upper :]
|
||||
|
||||
94
crates/ruff_linter/resources/test/fixtures/pycodestyle/E703.ipynb
vendored
Normal file
94
crates/ruff_linter/resources/test/fixtures/pycodestyle/E703.ipynb
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "33faf7ad-a3fd-4ac4-a0c3-52e507ed49df",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"x = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "481fb4bf-c1b9-47da-927f-3cfdfe4b49ec",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Simple case\n",
|
||||
"x;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "2f0c65a5-0a0e-4080-afce-5a8ed0d706df",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Only skip the last expression\n",
|
||||
"x; # E703\n",
|
||||
"x;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "5a3fd75d-26d9-44f7-b013-1684aabfd0ae",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Nested expressions isn't relevant\n",
|
||||
"if True:\n",
|
||||
" x;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "05eab5b9-e2ba-4954-8ef3-b035a79573fe",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Semicolons with multiple expressions\n",
|
||||
"x; x;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "9cbbddc5-83fc-4fdb-81ab-53a3912ae898",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Comments, newlines and whitespace\n",
|
||||
"x; # comment\n",
|
||||
"\n",
|
||||
"# another comment"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python (ruff-playground)",
|
||||
"language": "python",
|
||||
"name": "ruff-playground"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -16,6 +16,48 @@ if False == None: # E711, E712 (fix)
|
||||
if None == False: # E711, E712 (fix)
|
||||
pass
|
||||
|
||||
named_var = []
|
||||
if [] is []: # F632 (fix)
|
||||
pass
|
||||
if named_var is []: # F632 (fix)
|
||||
pass
|
||||
if [] is named_var: # F632 (fix)
|
||||
pass
|
||||
if named_var is [1]: # F632 (fix)
|
||||
pass
|
||||
if [1] is named_var: # F632 (fix)
|
||||
pass
|
||||
if named_var is [i for i in [1]]: # F632 (fix)
|
||||
pass
|
||||
|
||||
named_var = {}
|
||||
if {} is {}: # F632 (fix)
|
||||
pass
|
||||
if named_var is {}: # F632 (fix)
|
||||
pass
|
||||
if {} is named_var: # F632 (fix)
|
||||
pass
|
||||
if named_var is {1}: # F632 (fix)
|
||||
pass
|
||||
if {1} is named_var: # F632 (fix)
|
||||
pass
|
||||
if named_var is {i for i in [1]}: # F632 (fix)
|
||||
pass
|
||||
|
||||
named_var = {1: 1}
|
||||
if {1: 1} is {1: 1}: # F632 (fix)
|
||||
pass
|
||||
if named_var is {1: 1}: # F632 (fix)
|
||||
pass
|
||||
if {1: 1} is named_var: # F632 (fix)
|
||||
pass
|
||||
if named_var is {1: 1}: # F632 (fix)
|
||||
pass
|
||||
if {1: 1} is named_var: # F632 (fix)
|
||||
pass
|
||||
if named_var is {i: 1 for i in [1]}: # F632 (fix)
|
||||
pass
|
||||
|
||||
###
|
||||
# Non-errors
|
||||
###
|
||||
@@ -33,3 +75,45 @@ if False is None:
|
||||
pass
|
||||
if None is False:
|
||||
pass
|
||||
|
||||
named_var = []
|
||||
if [] == []:
|
||||
pass
|
||||
if named_var == []:
|
||||
pass
|
||||
if [] == named_var:
|
||||
pass
|
||||
if named_var == [1]:
|
||||
pass
|
||||
if [1] == named_var:
|
||||
pass
|
||||
if named_var == [i for i in [1]]:
|
||||
pass
|
||||
|
||||
named_var = {}
|
||||
if {} == {}:
|
||||
pass
|
||||
if named_var == {}:
|
||||
pass
|
||||
if {} == named_var:
|
||||
pass
|
||||
if named_var == {1}:
|
||||
pass
|
||||
if {1} == named_var:
|
||||
pass
|
||||
if named_var == {i for i in [1]}:
|
||||
pass
|
||||
|
||||
named_var = {1: 1}
|
||||
if {1: 1} == {1: 1}:
|
||||
pass
|
||||
if named_var == {1: 1}:
|
||||
pass
|
||||
if {1: 1} == named_var:
|
||||
pass
|
||||
if named_var == {1: 1}:
|
||||
pass
|
||||
if {1: 1} == named_var:
|
||||
pass
|
||||
if named_var == {i: 1 for i in [1]}:
|
||||
pass
|
||||
|
||||
@@ -663,3 +663,55 @@ class CommentAfterDocstring:
|
||||
def newline_after_closing_quote(self):
|
||||
"We enforce a newline after the closing quote for a multi-line docstring \
|
||||
but continuations shouldn't be considered multi-line"
|
||||
|
||||
|
||||
|
||||
|
||||
def retain_extra_whitespace():
|
||||
"""Summary.
|
||||
|
||||
This is overindented
|
||||
And so is this, but it we should preserve the extra space on this line relative
|
||||
to the one before
|
||||
"""
|
||||
|
||||
|
||||
def retain_extra_whitespace_multiple():
|
||||
"""Summary.
|
||||
|
||||
This is overindented
|
||||
And so is this, but it we should preserve the extra space on this line relative
|
||||
to the one before
|
||||
This is also overindented
|
||||
And so is this, but it we should preserve the extra space on this line relative
|
||||
to the one before
|
||||
"""
|
||||
|
||||
|
||||
|
||||
def retain_extra_whitespace_deeper():
|
||||
"""Summary.
|
||||
|
||||
This is overindented
|
||||
And so is this, but it we should preserve the extra space on this line relative
|
||||
to the one before
|
||||
And the relative indent here should be preserved too
|
||||
"""
|
||||
|
||||
def retain_extra_whitespace_followed_by_same_offset():
|
||||
"""Summary.
|
||||
|
||||
This is overindented
|
||||
And so is this, but it we should preserve the extra space on this line relative
|
||||
This is overindented
|
||||
This is overindented
|
||||
"""
|
||||
|
||||
|
||||
def retain_extra_whitespace_not_overindented():
|
||||
"""Summary.
|
||||
|
||||
This is not overindented
|
||||
This is overindented, but since one line is not overindented this should not raise
|
||||
And so is this, but it we should preserve the extra space on this line relative
|
||||
"""
|
||||
|
||||
43
crates/ruff_linter/resources/test/fixtures/pydocstyle/D100.ipynb
vendored
Normal file
43
crates/ruff_linter/resources/test/fixtures/pydocstyle/D100.ipynb
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "33faf7ad-a3fd-4ac4-a0c3-52e507ed49df",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Hello world!\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(\"Hello world!\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python (ruff-playground)",
|
||||
"language": "python",
|
||||
"name": "ruff-playground"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
4
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_21.py
vendored
Normal file
4
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_21.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
"""Test for IPython-only builtins."""
|
||||
|
||||
x = 1
|
||||
display(x)
|
||||
74
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_22.ipynb
vendored
Normal file
74
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_22.ipynb
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "af8fee97-f9aa-47c2-b34c-b109a5f083d6",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "acd5eb1e-6991-42b8-806f-20d17d7e571f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"display(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f8f3f599-030e-48b3-bcd3-31d97f725c68",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
7
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_23.py
vendored
Normal file
7
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_23.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
"""Test for type annotation parsing in `NamedTuple`."""
|
||||
|
||||
import typing
|
||||
|
||||
User = typing.NamedTuple('User', **{'name': str, 'password': bytes})
|
||||
User = typing.NamedTuple('User', name=str, password=bytes)
|
||||
User = typing.NamedTuple('User', [('name', str), ('password', bytes)])
|
||||
@@ -50,7 +50,7 @@ class Apples:
|
||||
return "Docstring"
|
||||
|
||||
# Added in Python 3.12
|
||||
def __buffer__(self):
|
||||
def __buffer__(self):
|
||||
return memoryview(b'')
|
||||
|
||||
def __release_buffer__(self, buf):
|
||||
@@ -83,6 +83,10 @@ class Apples:
|
||||
def _(self):
|
||||
pass
|
||||
|
||||
# Allow custom dunder names (via setting).
|
||||
def __special_custom_magic__(self):
|
||||
pass
|
||||
|
||||
|
||||
def __foo_bar__(): # this is not checked by the [bad-dunder-name] rule
|
||||
...
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user