astral-sh / ruff Goto Github PK
View Code? Open in Web Editor NEWAn extremely fast Python linter and code formatter, written in Rust.
Home Page: https://docs.astral.sh/ruff
License: MIT License
An extremely fast Python linter and code formatter, written in Rust.
Home Page: https://docs.astral.sh/ruff
License: MIT License
ruff foo/bar/non_existent_file.py
runs without issue (but should error).
Code:
def dec(x):
return x
@dec
def f():
dec = 1
return dec
Error:
./tmp.py:6:5: F832 Local variable `dec` referenced before assignment
pylint does this properly, Flake8 does not.
For example, with this:
import multiprocessing.pool
import multiprocessing.process
Flake8 will only mark the second import as unused.
Hi Charlie,
maybe similar to #83, ruff
also marks spots as "imported but unused", where the imported symbols are only used within type hints.
With kind regards,
Andreas.
import dataclasses
from datetime import datetime
@dataclasses.dataclass
class Message:
message: str
datetime: datetime
https://pypi.org/project/black/ is a very popular auto code formatter / style guide.
Many tools include documentation that specifically lay out how to configure said tool to conform to black. I think that would be a helpful subsection.
👋 Hi there!
I found this feature in the GitHub CLI application and npm.
I think it'll be useful for users who install ruff
via PyPi
.
And this will let them know that a new version is available and it's time to update.
Ready-made crate to implement that: update-informer
Limited to only the checks I support.
Right now, we're able to get away with a single visitor implementation that implements all rules. We'll need to evolve this to something closer to Fixit's model: multiple visitors that deal with isolated concerns, and can be batched and run in a single traversal.
If I run ruff on a file containing a class with a type annotation at class level, it incorrectly gives F821 (undefined name).
Examples:
from dataclasses import dataclass
@dataclass
class Bad:
x: int
@dataclass
class AlsoBad:
x: int = 3
class StillBad:
x: int
def __init__(self):
self.x = 3
class Ok:
x = 3
Running ruff <filename>
on this file gives:
ruff_test.py:6:5: F821 Undefined name `x`
ruff_test.py:11:5: F821 Undefined name `x`
ruff_test.py:15:5: F821 Undefined name `x`
(flake8 gives no errors)
Ruff version 0.0.28, python 3.8.13, ubuntu 22.04.1.
It would be nice to have pre-commit support. How to create new hooks in case it is needed.
It can wait… Definitely not an urgent task.
Is there a way to add ruff as a python linter in VScode?
Ruff looks great, congratulations. I'd love to use it one day on pydantic instead of flake8.
The following code is valid python and runs fine
def main():
foo()
def foo():
print('this is foo')
main()
However ruff returns:
test.py:2:5: F821 Undefined name `foo`
Found 1 error(s).
Running ruff on pydantic's code base is currently returning 151 F821
errors, so it's a fairly common problem.
Since #119 was fixed via #125, I tried ruff again (build from main
) with pydantic.
I get a few remaining F821
errors due to use of strings in Literal
, the line numbers are also incorrect - seems to always be 1
.
From this code (and some other places in that file), I get:
pydantic/config.py:1:1: F821 Undefined name `deep`
pydantic/config.py:1:1: F821 Undefined name `none`
pydantic/config.py:1:1: F821 Undefined name `deep`
pydantic/config.py:1:1: F821 Undefined name `shallow`
pydantic/config.py:1:1: F821 Undefined name `before_validation`
pydantic/config.py:1:1: F821 Undefined name `after_validation`
pydantic/config.py:1:1: F821 Undefined name `none`
pydantic/config.py:1:1: F821 Undefined name `shallow`
pydantic/config.py:1:1: F821 Undefined name `before_validation`
pydantic/config.py:1:1: F821 Undefined name `after_validation`
Example code:
copy_on_model_validation: Literal['none', 'deep', 'shallow']
post_init_call: Literal['before_validation', 'after_validation']
Not critical but this could be somewhat useful for autofixing. Similar to astor. The main issue with AST-to-code generation is that it's impossible to preserve formatting, including comments and docstrings, since those aren't captured in the AST. That's a big limitation, and means that you can really only use this for reconstructing small subtrees.
Dear Charlie,
thanks a stack for conceiving this excellent program. While working on modernizing an outdated code base [1,2], we started using ruff
just recently, and are amazed by its speed. Currently, we would never look back.
As we got the chance to work on this code base, originally from Python 2, but now already ported to Python 3 and polished off with ruff
and black
, we thought it would be a good idea to report back what flake8
would still observe on it.
The error codes are: E203, E711, E712, E713, E741, F841, where E712 was the most popular, followed by its neighbors E711 and E713, as well as F841.
With kind regards,
Andreas.
[1] https://github.com/isarengineering/SecPi/tree/next
[2] SecPi/SecPi#120
There are cases where _
cannot be used to mark a throwaway variable and it would be great if ruff allowed configuring it. This is common in projects that use gettext
for example, as _
is used for translating strings there. One of the ways unused variables are marked in such projects is using __
(double underscore) but it probably would be a good idea to just make it configurable with a sane default to appeal to more uses.
Notably, pylint allows configuring the dummy variable pattern with a regex:
https://pylint.pycqa.org/en/latest/user_guide/configuration/all-options.html#dummy-variables-rgx
Steps to reproduce
__init__.py
and blah.py
.blah.py
class MyBlahClass:
pass
__init__.py
from blah import MyBlahClass
__all__ = ["MyBlahClass"]
Expected results
2. ruff should not have an issue with the import in MyBlahClass
as it's included in __all__
.
Actual results
2. ruff reports a F401, class imported but unused
ruff output:
ruff . -v
[2022-09-01][15:17:28][ruff][DEBUG] Identified files to lint in: 25.778µs
[2022-09-01][15:17:28][ruff::linter][DEBUG] Cache hit for: ./blah.py
[2022-09-01][15:17:28][ruff::linter][DEBUG] Cache hit for: ./__init__.py
[2022-09-01][15:17:28][ruff][DEBUG] Checked files in: 588.674µs
Found 1 error(s).
./__init__.py:1:1: F401 `blah.MyBlahClass` imported but unused
flake8 output:
flake8 . -v
flake8.checker MainProcess 53 INFO Making checkers
flake8.checker MainProcess 54 INFO Checking 2 files
flake8.main.application MainProcess 71 INFO Finished running
flake8.main.application MainProcess 71 INFO Reporting errors
flake8.main.application MainProcess 71 INFO Found a total of 0 violations and reported 0
Hi again,
after running into #119 as well, we tried to ignore F821
by adding it to the pyproject.toml
file within the [tool.ruff]
section, like:
[tool.ruff]
ignore = ["F821"]
However, ruff
complained with:
Failed to load pyproject.toml: unknown field `ignore`, expected one of `line-length`, `exclude`, `select` for key `tool.ruff` at line 199 column 1
It looks like the option, although being implemented within settings.rs
, is currently only available as a command line option, to be used like ruff --ignore=F821 .
. I think it would be sweet to be en par with flake8
in this case, because ignore
will probably be a popular option.
With kind regards,
Andreas.
I tried running ruff on a large project, which resulted in this crash:
[2022-08-31][10:33:40][ruff][ERROR] Failed to check repr-with.py: invalid syntax. Got unexpected token 'as' at line 9 column 13
It seems like the crash happens on parenthesized context managers introduced in Python 3.10. Minimal reproducible example:
from contextlib import contextmanager
@contextmanager
def ctx():
yield
with (ctx() as foo):
...
main.py
from flask import Flask
def make_app():
app = Flask(__name__)
return app
app = make_app()
Results:
$ ruff main.py
Found 1 error(s).
main.py:7:7: F821 Undefined name `make_app`
$ flake8 main.py
main.py:3:1: E302 expected 2 blank lines, found 1
main.py:7:1: E305 expected 2 blank lines after class or function definition, found 1
With many Django apps in one project, one usually has a lot of auto-generated DB migrations, each under its own app directory. It looks like so:
apps/foo/migrations/...
apps/bar/migrations/...
It would be great to be able to match them in one exclude pattern, like apps/*/migrations
, or, **/migrations/
, or even just /migrations/
.
None of these appears to work right now; the only to list every app explicitly.
PyFlakes has a variety of checks that require being able to traverse up the "parent" tree for any node.
RUST_BACKTRACE=full ruff celery
thread '<unnamed>' panicked at 'removal index (is 20) should be < len (is 20)', src/check_lines.rs:35:16
stack backtrace:
0: 0x10ca52807 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h85521558a183f368
1: 0x10c876a4b - core::fmt::write::h01631fae0d2b98bc
2: 0x10ca4d8bc - std::io::stdio::_print::h3f48a1f06c5dc1b5
3: 0x10ca56db0 - std::panicking::default_hook::h18647b59f1a84ee2
4: 0x10ca56acc - std::panicking::default_hook::h18647b59f1a84ee2
5: 0x10ca57368 - std::panicking::rust_panic_with_hook::hd9ead35a68ccc55e
6: 0x10ca572a4 - <std::panicking::begin_panic_handler::StrPanicPayload as core::panic::BoxMeUp>::get::h4eaac086dd1f05c5
7: 0x10ca55da7 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h85521558a183f368
8: 0x10ca56fc0 - _rust_begin_unwind
9: 0x10ca7f683 - core::panicking::panic_fmt::h3d9f795ee387ef8d
10: 0x10ca7b176 - alloc::vec::Vec<T,A>::remove::assert_failed::h110daa08131a2fb6
11: 0x10c9232a8 - ruff::linter::check_path::he0f23175143f4a67
12: 0x10c938891 - ruff::settings::Settings::ignore::h00b9e252c6691a0f
13: 0x10c936a43 - ruff::settings::Settings::ignore::h00b9e252c6691a0f
14: 0x10c92a320 - ruff::settings::Settings::ignore::h00b9e252c6691a0f
15: 0x10c936ddf - ruff::settings::Settings::ignore::h00b9e252c6691a0f
16: 0x10c92a3ff - ruff::settings::Settings::ignore::h00b9e252c6691a0f
17: 0x10c936ddf - ruff::settings::Settings::ignore::h00b9e252c6691a0f
18: 0x10c92a3ff - ruff::settings::Settings::ignore::h00b9e252c6691a0f
19: 0x10c936ddf - ruff::settings::Settings::ignore::h00b9e252c6691a0f
20: 0x10c92a320 - ruff::settings::Settings::ignore::h00b9e252c6691a0f
21: 0x10c936ddf - ruff::settings::Settings::ignore::h00b9e252c6691a0f
22: 0x10c937693 - ruff::settings::Settings::ignore::h00b9e252c6691a0f
23: 0x10ca82306 - rayon_core::registry::WorkerThread::wait_until_cold::h6c4b4c23a2ed2f5c
24: 0x10c92a4d2 - ruff::settings::Settings::ignore::h00b9e252c6691a0f
25: 0x10c936ddf - ruff::settings::Settings::ignore::h00b9e252c6691a0f
26: 0x10c937693 - ruff::settings::Settings::ignore::h00b9e252c6691a0f
27: 0x10ca82306 - rayon_core::registry::WorkerThread::wait_until_cold::h6c4b4c23a2ed2f5c
28: 0x10c8acdf0 - rayon_core::registry::ThreadBuilder::run::ha91e61928ff63c4e
29: 0x10c8a9e72 - _rust_eh_personality
30: 0x10c8ab17f - _rust_eh_personality
31: 0x10ca5a8f9 - std::sys::unix::thread::Thread::new::h2ee6b50b075520a6
32: 0x7ff80e4b94e1 - __pthread_start
zsh: abort RUST_BACKTRACE=full ruff celery
Hey!
Great project! I just found a bug that occurs if ruff
cannot find a pyproject.toml
file. It will assume that
there is a pyproject.toml
file at $HOME/.ruff
. When trying to parse it, the program crashes (silently) with a file not found error.
To reproduce:
Try running ruff
in a location where it cannot find a pyproject.toml
file at all.
I already forked and fixed the bug :)
Consider using https://pypi.org/project/hypothesmith/
It generates lots of python programms to run your tool on.
It really helps finding ones that crash.
Example: https://github.com/wemake-services/wemake-python-styleguide/blob/master/tests/test_checker/test_hypothesis.py
As mentioned in #119, ruff looks great and I'd love to adopt it in pydantic, however I'd like to have a better understanding of what I loose by switching from flake8 to ruff?
I've run ruff on pydantic and apart from #119, ruff has found a few legitimate things that I would either fix or ignore. The problem is what checks am I no longer getting?
This is harder to find without either a lot of trial or waiting to get bitten.
I would therefore find it really helpful if there was a good comparison of ruff and flake8. I'm sure other potential users would also find this helpful.
ruff marks from __future__ import annotations
imports as unused. They are not supposed to be used, and so shouldn't be reported.
models.py:1:1: F401 `__future__.annotations` imported but unused
We can't upload to crates.io because we're using an unreleased version of RustPython.
Tracked here: RustPython/RustPython#4099
https://github.com/Instagram/LibCST
It is partially written in Rust and allows you to have way more over the syntax tree.
It will allow code rewrite and will allow more syntax checks.
I highly recommend trying this before the project will have a lot of exisiting source code.
There's a lot of awesome flake8 extensions… Is there a plan to support those?
I suspect that it won't be possible to just add them as the underlying code is so different.
If you import a symbol, and only use it as a forward-reference type annotation, we mark the import as unused.
Found this bug while testing ruff on my code, here is a simplified example to reproduce:
main.py
:
with (
open("test", "r") as f,
open("test2", "r") as f2,
):
print("hello")
ruff output:
[2022-09-01][14:00:00][ruff::pyproject][DEBUG] Found pyproject.toml at: pyproject.toml
[2022-09-01][14:00:00][ruff][DEBUG] Identified files to lint in: 3.25µs
[2022-09-01][14:00:00][ruff][ERROR] Failed to check main.py: invalid syntax. Got unexpected token 'as' at line 2 column 23
[2022-09-01][14:00:00][ruff][DEBUG] Checked files in: 174.625µs
Found 0 error(s).
It'd be useful to have a way to lint all Python files in a directory and its subdirectories using a CLI option.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.