Commit Graph

148 Commits

Author SHA1 Message Date
konstin 6a52577630
Ecosystem CI: Allow storing checkouts locally (#4192)
* Ecosystem CI: Allow storing checkouts locally

This adds a --checkouts options to (re)use a local directory instead of checkouts into a tempdir

* Fix missing path conversion
2023-05-11 17:36:44 +02:00
Calum Young b76b4b6016
List rule changes in ecosystem (#4371)
* Count changes for each rule

* Handle case where rule matches were found in a line

* List and sort by changes

* Remove detail from rule changes

* Add comment about leading :

* Only print rule changes if rule changes are present

* Use re.search and match group

* Remove dict().items()

* Use match group to extract rule code
2023-05-11 16:33:15 +02:00
konstin 0096938789
Optionally show fixes when using `--features ecosystem_ci` with cargo and `--show-fixes` at runtime (#4191)
* Generate fixes when using --show-fixes

Example command: `cargo run --bin ruff -- --no-cache --select F401
--show-source --show-fixes
crates/ruff/resources/test/fixtures/pyflakes/F401_9.py`

Before, `--show-fixes` was ignored:

```
crates/ruff/resources/test/fixtures/pyflakes/F401_9.py:4:22: F401 [*] `foo.baz` imported but unused
  |
4 | __all__ = ("bar",)
5 | from foo import bar, baz
  |                      ^^^ F401
  |
  = help: Remove unused import: `foo.baz`

Found 1 error.
[*] 1 potentially fixable with the --fix option.
```

After:

```
crates/ruff/resources/test/fixtures/pyflakes/F401_9.py:4:22: F401 [*] `foo.baz` imported but unused
  |
4 | __all__ = ("bar",)
5 | from foo import bar, baz
  |                      ^^^ F401
  |
  = help: Remove unused import: `foo.baz`

ℹ Suggested fix
1 1 | """Test: late-binding of `__all__`."""
2 2 |
3 3 | __all__ = ("bar",)
4   |-from foo import bar, baz
  4 |+from foo import bar

Found 1 error.
[*] 1 potentially fixable with the --fix option.
```

* Add `--format ecosystem-ci`

* cargo dev generate-all

* Put behind cargo feature

* Regenerate docs

* Don't test ecosystem_ci feature on CI

* Use top level flag instead

* Fix

* Simplify code based on #4191

* Remove old TODO comment
2023-05-10 17:45:57 +02:00
Calum Young 03f141f53d
Check that all rules have descriptions (#4315) 2023-05-09 16:53:23 +00:00
Calum Young 8dea47afc1
Update `mkdocs` unformatted example error message (#4312) 2023-05-09 12:36:13 -04:00
Calum Young cd41de2588
Check docs formatting check (#4270) 2023-05-08 19:03:22 +00:00
Aarni Koskela d7a369e7dc
Update confusable character mapping (#4274) 2023-05-08 14:20:44 -04:00
Jonathan Plasse a32617911a
Use --filter=blob:none to clone CPython faster (#4156) 2023-04-30 13:39:22 +02:00
Micha Reiser cab65b25da
Replace row/column based `Location` with byte-offsets. (#3931) 2023-04-26 18:11:02 +00:00
konstin 19d8913e32
Use musl in ecosystem docker (#3998)
This prevents errors when the host glibc is newer than the one in the docker container
2023-04-26 05:54:53 +02:00
Charlie Marsh e160a52bfd
Raise percent-format upgrade rule (`UP031`) for hanging modulos (#3953) 2023-04-12 23:59:20 -04:00
Micha Reiser e8aebee3f6
Pretty print `Diagnostic`s in snapshot tests (#3906) 2023-04-11 09:03:00 +00:00
konstin 454c6d9c2f
Extended ecosystem check with scraped data (#3858) 2023-04-06 22:39:48 +00:00
Jonathan Plasse f3f9a9f297
Fix pre-commit CI job exit code (#3833) 2023-03-31 14:47:04 -04:00
Jonathan Plasse fec4fa39a7
Improve `add_rule.py` and `add_plugin.py` scripts (#3725) 2023-03-25 16:05:39 +00:00
Jonathan Plasse 7f3b748401
Fix Ruff pre-commit hook errors (#3706) 2023-03-23 22:52:24 -04:00
Zhengbo Wang b08326162b
Doc/CLN: pass pre-commit (#3604) 2023-03-19 19:20:11 +00:00
Henry Schreiner 4bdb2dd362
ci(check_ecosystem): add PyPa/build (#3569) 2023-03-18 19:09:22 -04:00
Henry Schreiner 53a4743631
ci: fix check_ecosystem (#3602) 2023-03-18 19:03:08 -04:00
Charlie Marsh 16a350c731
Reduce usage of ALL in ecosystem CI (#3590) 2023-03-18 13:13:09 -04:00
Henry Schreiner d9ed0aae69
ci(check_ecosystem): add cibuildwheel (#3567) 2023-03-16 22:34:56 -04:00
Henry Schreiner bbc87b7177
ci(check_ecosystem): add scikit-build-core (#3563) 2023-03-16 19:46:42 -04:00
Xuehai Pan e99e1fae2b
ci: add `python/typeshed` to ecosystem check (#3559) 2023-03-16 14:19:48 -04:00
Calum Young 6c576872d4
List changes for all ecosystem repos (#3461) 2023-03-12 14:30:38 -04:00
Charlie Marsh 7062d1db16
Run ecosystem CI checks without --isolated (#3445) 2023-03-10 19:03:51 -05:00
Samuel Cormier-Iijima cfa2924664
Setup ecosystem CI (#3390)
This PR sets up an "ecosystem" check as an optional part of the CI step for pull requests. The primary piece of this is a new script in `scripts/check_ecosystem.py` which takes two ruff binaries as input and compares their outputs against a corpus of open-source code in parallel. I used ruff's `text` reporting format and stdlib's `difflib` (rather than JSON output and jsondiffs) to avoid adding another dependency. There is a new ecosystem-comment workflow to add a comment to the PR (see [this link](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) which explains why it needs to be done as a new workflow for security reasons).
2023-03-10 17:39:07 -05:00
Charlie Marsh 024caca233
Introduce a `ruff_diagnostics` crate (#3409)
## Summary

This PR moves `Diagnostic`, `DiagnosticKind`, and `Fix` into their own crate, which will enable us to further split up Ruff, since sub-linter crates (which need to implement functions that return `Diagnostic`) can now depend on `ruff_diagnostics` rather than Ruff.
2023-03-09 20:48:57 +00:00
konstin 348a38d261
Deprecate define violation (#3358)
* Add `#[violation]` proc macro as a replacement for `define_violation!`

* Switch all rules to #[violation]
2023-03-06 10:59:06 +00:00
konstin 2168404fc2
flake8-pyi PYI006 bad version info comparison (#3291)
Implement PYI006 "bad version info comparison"

## What it does

Ensures that you only `<` and `>=` for version info comparisons with
`sys.version_info` in `.pyi` files. All other comparisons such as
`<`, `<=` and `==` are banned.

## Why is this bad?

```python
>>> import sys
>>> print(sys.version_info)
sys.version_info(major=3, minor=8, micro=10, releaselevel='final', serial=0)
>>> print(sys.version_info > (3, 8))
True
>>> print(sys.version_info == (3, 8))
False
>>> print(sys.version_info <= (3, 8))
False
>>> print(sys.version_info in (3, 8))
False
```

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-03-01 18:58:57 +01:00
Charlie Marsh 8066607ea3
Add a preliminary tutorial (#3281) 2023-02-28 20:31:27 +00:00
Jonathan Plasse d285f5c90a
Run automatically format code blocks with Black (#3191) 2023-02-27 10:14:05 -05:00
Carlos Gonçalves 1c01b3c934
fix(docs): broken links inside Configuration.md (#3205) 2023-02-24 18:55:33 +00:00
Jonathan Plasse 39b9a1637f
Fix Markdown errors in docs (#3187) 2023-02-24 13:06:48 -05:00
Jonathan Plasse 6e54cd8233
Normalize relative markdown links (#3190) 2023-02-23 16:24:31 -05:00
Jonathan Plasse a688a237d7
Add black to pre-commit (#3192) 2023-02-23 16:24:23 -05:00
Charlie Marsh 74e18b6cff
Split up some docs sections (#3154) 2023-02-22 20:18:10 -05:00
Charlie Marsh b9bfb81e36
Move configuration out of README and into permanent docs (#3150) 2023-02-22 19:25:53 -05:00
Micha Reiser f72ed255e5
chore: Use `LF` on all platforms (#3005)
I worked on #2993 and ran into issues that the formatter tests are failing on Windows because `writeln!` emits `\n` as line terminator on all platforms, but `git` on Windows converted the line endings in the snapshots to `\r\n`.

I then tried to replicate the issue on my Windows machine and was surprised that all linter snapshot tests are failing on my machine. I figured out after some time that it is due to my global git config keeping the input line endings rather than converting to `\r\n`. 

Luckily, I've been made aware of #2033 which introduced an "override" for the `assert_yaml_snapshot` macro that normalizes new lines, by splitting the formatted string using the platform-specific newline character. This is a clever approach and gives nice diffs for multiline fixes but makes assumptions about the setup contributors use and requires special care whenever we use line endings inside of tests. 

I recommend that we remove the special new line handling and use `.gitattributes` to enforce the use of `LF` on all platforms [guide](https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings). This gives us platform agnostic tests without having to worry about line endings in our tests or different git configurations.

## Note

It may be necessary for Windows contributors to run the following command to update the line endings of their files

```bash
git rm --cached -r .
git reset --hard
```
2023-02-20 20:13:37 +00:00
Charlie Marsh c25be31eb1
Fix documentation-link detection in generate_mkdocs.py (#3030) 2023-02-19 12:20:44 +00:00
Charlie Marsh cd1f57b713
Move FAQ into MkDocs (#2984) 2023-02-17 13:15:53 +00:00
Charlie Marsh a0912deb2b
Move editor integrations into MkDocs (#2983) 2023-02-17 13:12:20 +00:00
Martin Fischer d658bfc024 Remove options from README 2023-02-17 07:55:50 -05:00
Martin Fischer 8195873cdf Remove rule tables from README 2023-02-17 07:55:50 -05:00
Charlie Marsh 298498e934
Add an Acknowledgements section to the README (#2907) 2023-02-15 00:25:07 +00:00
Martin Fischer 860993187e Fix link relativization in generate_mkdocs.py 2023-02-14 17:56:21 -05:00
Martin Fischer c314e10e54 many-to-one 6/9: Implement ruff_macros::map_codes 2023-02-14 16:16:12 -05:00
Martin Fischer 65a3461519 many-to-one 4/9: Rename define_rule_mapping! to register_rules!
Currently the define_rule_mapping! macro generates both the Rule enum as
well as the RuleCodePrefix enum and the mapping between the two.  After
this commit series the macro will only generate the Rule enum and the
RuleCodePrefix enum and the mapping will be generated by a new map_codes
proc macro, so we rename the macro now to fit its new purpose.
2023-02-14 16:16:12 -05:00
Martin Fischer 02285c18d1 Remove autogenerated docs/rules/*.md files 2023-02-13 19:34:06 -05:00
Simon Brugman f8ac6d7bf0
fix: script `add_plugin.py` test import (#2807) 2023-02-12 09:58:23 -05:00
Charlie Marsh 271e4fda8c
Create per-rule pages and link from README (#2644) 2023-02-07 18:15:05 -05:00
Charlie Marsh f1cdd108e6
Derive `explanation` method on Rule struct via rustdoc (#2642)
```console
❯ cargo run rule B017
    Finished dev [unoptimized + debuginfo] target(s) in 0.13s
     Running `target/debug/ruff rule B017`
no-assert-raises-exception

Code: B017 (flake8-bugbear)

### What it does
Checks for `self.assertRaises(Exception)`.

## Why is this bad?
`assertRaises(Exception)` can lead to your test passing even if the
code being tested is never executed due to a typo.

Either assert for a more specific exception (builtin or custom), use
`assertRaisesRegex` or the context manager form of `assertRaises`.
```
2023-02-07 17:23:29 -05:00
Charlie Marsh 87d0aa5561
Move `python` into its own `ruff_python` crate (#2593) 2023-02-05 17:53:58 -05:00
Micha Reiser cd8be8c0be
refactor: Introduce crates folder (#2088)
This PR introduces a new `crates` directory and moves all "product" crates into that folder. 

Part of #2059.
2023-02-05 16:47:48 -05:00
Jonathan Plasse bdcab87d2f
Add `markdownlint` and dev Ruff to `pre-commit` (#2303) 2023-02-02 16:29:07 -05:00
Jonathan Plasse ec8b827d26
Add known-standard-library for each Python version (#2491) 2023-02-02 16:22:47 -05:00
Jonathan Plasse b232c43824
Fix an error in scripts/add_rule.py (#2497) 2023-02-02 15:58:11 -05:00
Jonathan Plasse e89b4a5de5
Fix hardcoded url in transform_readme.py (#2487) 2023-02-02 13:59:22 -05:00
Charlie Marsh f432ce291a Add Fathom to docs 2023-02-01 18:41:24 -05:00
Charlie Marsh 69e20c4554
Minor improvements to the docs (#2371) 2023-01-30 19:06:05 -05:00
Charlie Marsh fc9fae6579 Remove picture tag from PyPI and MkDocs 2023-01-28 11:49:52 -05:00
Charlie Marsh 071e3fd196
Split MkDocs site into multiple pages (#2296) 2023-01-28 08:31:16 -05:00
Charlie Marsh eaac3cae5e
Add MkDocs version of README (#2287)
Co-authored-by: Justin Flannery <juftin@juftin.com>
2023-01-27 22:57:42 -05:00
Simon Brugman bab8691132
chore: fix script indent (#2213) 2023-01-26 13:53:22 -05:00
Simon Brugman 413acdf83c feat: introduce macro for testing snap files across platforms 2023-01-25 18:00:39 -05:00
Jonathan Plasse 82d7814101
Update .pre-commit-config.yml (#2139) 2023-01-24 19:45:34 -05:00
Martin Fischer 991d3c1ef6 refactor: Move Linter::url and Linter::name generation to proc macro
This lets us get rid of the build.rs script and results
in more developer-friendly compile error messages.
2023-01-23 12:20:10 -05:00
Simon Brugman 11f06055a0
feat: flake8-use-pathlib PTH100-124 (#2090) 2023-01-22 15:17:25 -05:00
alm e11cf1bf65
Update linters PyPI links to latest version (#2062) 2023-01-22 13:10:22 -05:00
Martin Fischer 1beedf20f9 fix: add_rule.py for --linter ruff 2023-01-22 11:51:29 -05:00
Martin Fischer 4758ee6ac4 refactor: Generate Linter -> RuleSelector mapping via macro
To enable ruff_dev to automatically generate the rule Markdown tables in
the README the ruff library contained the following function:

    Linter::codes() -> Vec<RuleSelector>

which was slightly changed to `fn prefixes(&self) -> Prefixes` in
9dc66b5a65 to enable ruff_dev to split
up the Markdown tables for linters that have multiple prefixes
(pycodestyle has E & W, Pylint has PLC, PLE, PLR & PLW).

The definition of this method was however largely redundant with the
#[prefix] macro attributes in the Linter enum, which are used to
derive the Linter::parse_code function, used by the --explain command.

This commit removes the redundant Linter::prefixes by introducing a
same-named method with a different signature to the RuleNamespace trait:

     fn prefixes(&self) -> &'static [&'static str];

As well as implementing IntoIterator<Rule> for &Linter. We extend the
extisting RuleNamespace proc macro to automatically derive both
implementations from the Linter enum definition.

To support the previously mentioned Markdown table splitting we
introduce a very simple hand-written method to the Linter impl:

    fn categories(&self) -> Option<&'static [LinterCategory]>;
2023-01-22 11:51:29 -05:00
Simon Brugman 28f05aa6e7
feat: update scripts to new rules structure (#2078)
- optional `prefix` argument for `add_plugin.py`
- rules directory instead of `rules.rs`
- pathlib syntax
- fix test case where code was added instead of name

Example:
```
python scripts/add_plugin.py --url https://pypi.org/project/example/1.0.0/ example --prefix EXA
python scripts/add_rule.py --name SecondRule --code EXA002 --linter example
python scripts/add_rule.py --name FirstRule --code EXA001 --linter example
python scripts/add_rule.py --name ThirdRule --code EXA003 --linter example
 ```

Note that it breaks compatibility with 'old style' plugins (generation works fine, but namespaces need to be changed):
```
python scripts/add_rule.py --name DoTheThing --code PLC999 --linter pylint
```
2023-01-21 19:19:58 -05:00
Martin Fischer 4e4643aa5d refactor: Decouple Rule from linter prefixes
543865c96b introduced
RuleCode::origin() -> RuleOrigin generation via a macro, while that
signature now has been renamed to Rule::origin() -> Linter we actually
want to get rid of it since rules and linters shouldn't be this tightly
coupled (since one rule can exist in multiple linters).

Another disadvantage of the previous approach was that the prefixes
had to be defined in ruff_macros/src/prefixes.rs, which was easy to
miss when defining new linters in src/*, case in point
INP001 => violations::ImplicitNamespacePackage has in the meantime been
added without ruff_macros/src/prefixes.rs being updated accordingly
which resulted in `ruff --explain INP001` mistakenly reporting that the
rule belongs to isort (since INP001 starts with the isort prefix "I").
The derive proc macro introduced in this commit requires every variant
to have at least one #[prefix = "..."], eliminating such mistakes.
2023-01-20 20:25:57 -05:00
Martin Fischer b19258a243 refactor: Rename RuleCodePrefix to RuleSelector
More accurate since the enum also encompasses:

* ALL (which isn't a prefix at all)

* fully-qualified rule codes (which aren't prefixes unless you say
  they're a prefix to the empty string but that's not intuitive)
2023-01-20 20:25:57 -05:00
Martin Fischer 7fc42f8f85 refactor: Rename RuleOrigin to Linter
"origin" was accurate since ruff rules are currently always modeled
after one origin (except the Ruff-specific rules).

Since we however want to introduce a many-to-many mapping between codes
and rules, the term "origin" no longer makes much sense. Rules usually
don't have multiple origins but one linter implements a rule first and
then others implement it later (often inspired from another linter).
But we don't actually care much about where a rule originates from when
mapping multiple rule codes to one rule implementation, so renaming
RuleOrigin to Linter is less confusing with the many-to-many system.
2023-01-20 20:25:57 -05:00
Martin Fischer 44e2b6208a fix: Update add_rule.py to create new files for rules 2023-01-20 08:09:54 -05:00
Martin Fischer 16c81f75c2 fix: Update add_rule.py to account for 16e79c8d 2023-01-20 08:09:54 -05:00
Martin Fischer e1d6ac3265 fix: Update add_plugin.py to account for 9dc66b5a 2023-01-20 08:09:54 -05:00
Martin Fischer 3aec1100f5 fix: Update add_plugin.py to account for b78b6f27 2023-01-20 08:09:54 -05:00
Martin Fischer c00df647e1 fix: Update add_rule.py to account for 81996f1bc 2023-01-20 08:09:54 -05:00
Martin Fischer f012877be1 Add scripts/pyproject.toml to use ruff for ruff :) 2023-01-20 08:09:54 -05:00
Martin Fischer ff6defc988 refactor: Introduce get_indent helper for scripts 2023-01-20 08:09:54 -05:00
Martin Fischer 67ca50e9f2 refactor: Reduce code duplication in scripts/ 2023-01-20 08:09:54 -05:00
Martin Fischer 6cc160bc2b Mark scripts/add_*.py as executable 2023-01-20 08:09:54 -05:00
Martin Fischer 6649225167 rule 8/8: Automatically rewrite RuleCode to Rule
# This commit was automatically generated by running the following
# script (followed by `cargo +nightly fmt`):

import glob
import re
from typing import NamedTuple

class Rule(NamedTuple):
    code: str
    name: str
    path: str

def rules() -> list[Rule]:
    """Returns all the rules defined in `src/registry.rs`."""
    file = open('src/registry.rs')

    rules = []

    while next(file) != 'ruff_macros::define_rule_mapping!(\n':
        continue

    while (line := next(file)) != ');\n':
        line = line.strip().rstrip(',')
        if line.startswith('//'):
            continue
        code, path = line.split(' => ')
        name = path.rsplit('::')[-1]
        rules.append(Rule(code, name, path))

    return rules

code2name = {r.code: r.name for r in rules()}

for pattern in ('src/**/*.rs', 'ruff_cli/**/*.rs', 'ruff_dev/**/*.rs', 'scripts/add_*.py'):
    for name in glob.glob(pattern, recursive=True):
        with open(name) as f:
            text = f.read()

        text = re.sub('Rule(?:Code)?::([A-Z]\w+)', lambda m: 'Rule::' + code2name[m.group(1)], text)
        text = re.sub(r'(?<!"<FilePattern>:<)RuleCode\b', 'Rule', text)
        text = re.sub('(use crate::registry::{.*, Rule), Rule(.*)', r'\1\2', text) # fix duplicate import

        with open(name, 'w') as f:
            f.write(text)
2023-01-18 23:51:48 -05:00
Charlie Marsh 2ed1f78873
Add benchmark scripts for no-IO (#1925) 2023-01-16 17:38:40 -05:00
Charlie Marsh 42031b8574
Re-run benchmark and update documentation (#1907)
Closes #269.
2023-01-16 01:38:58 -05:00
messense c7d0d26981
Update add plugin/rule scripts (#1889)
Adjusted some file locations and changed to use [`pathlib`](https://docs.python.org/3/library/pathlib.html) instead of `os.path`.
2023-01-15 12:49:42 -05:00
Charlie Marsh b36d4a15b0
Modify visibility and shuffle around some modules (#1807) 2023-01-11 23:57:05 -05:00
Martin Fischer 543865c96b
Generate RuleCode::origin() via macro (#1770) 2023-01-10 13:20:43 -05:00
Charlie Marsh 1a09fff991
Update rule-generation `scripts` to match latest conventions (#1758)
Resolves #1755.
2023-01-09 19:55:46 -05:00
Charlie Marsh 59155ce9f6
Rename `checks` and `plugins` to `rules` (#1739) 2023-01-09 01:39:51 -05:00
Charlie Marsh 09dc3c7225
Rename `Check` to `Diagnostic` (#1725)
Along with:

- `CheckKind` -> `DiagnosticKind`
- `CheckCode` -> `RuleCode`
- `CheckCodePrefix` -> `RuleCodePrefix`
2023-01-08 17:46:20 -05:00
Charlie Marsh ca7fe686d5
Add scripts to generate plugin and check boilerplate (#1579) 2023-01-02 22:10:31 -05:00
Charlie Marsh bad5723d80
Add plugin configuration to flake8-to-ruff (#535) 2022-11-01 17:08:53 -04:00
Charlie Marsh e73f13473d Add a .flake8 file for benchmarking 2022-10-14 17:05:24 -04:00
Charlie Marsh ea9fde14f6 Fix pyproject.toml key 2022-08-28 14:22:19 -04:00
Charlie Marsh 6c8794692b Tweak README 2022-08-27 21:10:44 -04:00
Charlie Marsh a5533d62e1 Enable benchmark for existing tools 2022-08-27 12:15:54 -04:00