Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90bfc4ec4d | ||
|
|
b04a6a3f7c | ||
|
|
8ec14e7ee2 | ||
|
|
17c5cd7c42 | ||
|
|
7d8360a1de | ||
|
|
910ee523dd | ||
|
|
72e35a535e | ||
|
|
b4e1563517 | ||
|
|
5717cc97d7 |
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.122
|
||||
rev: v0.0.124
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -930,7 +930,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.122-dev.0"
|
||||
version = "0.0.124-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
@@ -2238,7 +2238,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.122"
|
||||
version = "0.0.124"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_cmd",
|
||||
@@ -2287,7 +2287,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.122"
|
||||
version = "0.0.124"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
|
||||
@@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.122"
|
||||
version = "0.0.124"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
375
LICENSE
375
LICENSE
@@ -19,3 +19,378 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
The externally maintained libraries from which parts of the Software is derived
|
||||
are:
|
||||
|
||||
- Pyflakes, licensed as follows:
|
||||
"""
|
||||
Copyright 2005-2011 Divmod, Inc.
|
||||
Copyright 2013-2014 Florent Xicluna
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
- autoflake, licensed as follows:
|
||||
"""
|
||||
Copyright (C) 2012-2018 Steven Myint
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- Flake8, licensed as follows:
|
||||
"""
|
||||
== Flake8 License (MIT) ==
|
||||
|
||||
Copyright (C) 2011-2013 Tarek Ziade <tarek@ziade.org>
|
||||
Copyright (C) 2012-2016 Ian Cordasco <graffatcolmingov@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-2020, licensed as follows:
|
||||
"""
|
||||
Copyright (c) 2019 Anthony Sottile
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-annotations, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 - Present S. Co1
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-bandit, licensed as follows:
|
||||
"""
|
||||
Copyright (c) 2017 Tyler Wince
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-bugbear, licensed as follows:
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Łukasz Langa
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-comprehensions, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Adam Johnson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-print, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Joseph Kahn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-quotes, licensed as follows:
|
||||
"""
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
- isort, licensed as follows:
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Timothy Edmund Crosley
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
- pep8-naming, licensed as follows:
|
||||
"""
|
||||
Copyright © 2013 Florent Xicluna <florent.xicluna@gmail.com>
|
||||
|
||||
Licensed under the terms of the Expat License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- pycodestyle, licensed as follows:
|
||||
"""
|
||||
Copyright © 2006-2009 Johann C. Rocholl <johann@rocholl.net>
|
||||
Copyright © 2009-2014 Florent Xicluna <florent.xicluna@gmail.com>
|
||||
Copyright © 2014-2020 Ian Lee <IanLee1521@gmail.com>
|
||||
|
||||
Licensed under the terms of the Expat License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- pydocstyle, licensed as follows:
|
||||
"""
|
||||
Copyright (c) 2012 GreenSteam, <http://greensteam.dk/>
|
||||
|
||||
Copyright (c) 2014-2020 Amir Rachum, <http://amir.rachum.com/>
|
||||
|
||||
Copyright (c) 2020 Sambhav Kothari, <https://github.com/samj1912>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- pyupgrade, licensed as follows:
|
||||
"""
|
||||
Copyright (c) 2017 Anthony Sottile
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
4
flake8_to_ruff/Cargo.lock
generated
4
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.122"
|
||||
version = "0.0.124"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.122"
|
||||
version = "0.0.124"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.122-dev.0"
|
||||
version = "0.0.124-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
2
resources/test/fixtures/E501.py
vendored
2
resources/test/fixtures/E501.py
vendored
@@ -5,7 +5,7 @@
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
"""
|
||||
|
||||
_ = """Lorem ipsum dolor sit amet.
|
||||
_ = """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
|
||||
https://github.com/PyCQA/pycodestyle/pull/258/files#diff-841c622497a8033d10152bfdfb15b20b92437ecdea21a260944ea86b77b51533
|
||||
|
||||
|
||||
4
resources/test/fixtures/E731.py
vendored
4
resources/test/fixtures/E731.py
vendored
@@ -8,14 +8,14 @@ while False:
|
||||
|
||||
|
||||
f = object()
|
||||
#: E731
|
||||
f.method = lambda: "Method"
|
||||
|
||||
f = {}
|
||||
#: E731
|
||||
f["a"] = lambda x: x ** 2
|
||||
|
||||
f = []
|
||||
f.append(lambda x: x ** 2)
|
||||
|
||||
f = g = lambda x: x ** 2
|
||||
|
||||
lambda: "no-op"
|
||||
|
||||
10
resources/test/fixtures/N805.py
vendored
10
resources/test/fixtures/N805.py
vendored
@@ -1,5 +1,7 @@
|
||||
from abc import ABCMeta
|
||||
|
||||
import pydantic
|
||||
|
||||
|
||||
class Class:
|
||||
def bad_method(this):
|
||||
@@ -21,6 +23,14 @@ class Class:
|
||||
def static_method(x):
|
||||
return x
|
||||
|
||||
@pydantic.validator
|
||||
def lower(cls, my_field: str) -> str:
|
||||
pass
|
||||
|
||||
@pydantic.validator("my_field")
|
||||
def lower(cls, my_field: str) -> str:
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
...
|
||||
|
||||
|
||||
1
resources/test/fixtures/pyproject.toml
vendored
1
resources/test/fixtures/pyproject.toml
vendored
@@ -33,6 +33,7 @@ ignore-names = [
|
||||
]
|
||||
classmethod-decorators = [
|
||||
"classmethod",
|
||||
"pydantic.validator",
|
||||
]
|
||||
staticmethod-decorators = [
|
||||
"staticmethod",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.122"
|
||||
version = "0.0.124"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -225,6 +225,29 @@ pub fn is_super_call_with_arguments(func: &Expr, args: &[Expr]) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Format the module name for a relative import.
|
||||
pub fn format_import_from(level: Option<&usize>, module: Option<&String>) -> String {
|
||||
let mut module_name = String::with_capacity(16);
|
||||
if let Some(level) = level {
|
||||
for _ in 0..*level {
|
||||
module_name.push('.');
|
||||
}
|
||||
}
|
||||
if let Some(module) = module {
|
||||
module_name.push_str(module);
|
||||
}
|
||||
module_name
|
||||
}
|
||||
|
||||
/// Split a target string (like `typing.List`) into (`typing`, `List`).
|
||||
pub fn to_module_and_member(target: &str) -> (&str, &str) {
|
||||
if let Some(index) = target.rfind('.') {
|
||||
(&target[..index], &target[index + 1..])
|
||||
} else {
|
||||
("", target)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a location within a file (relative to `base`) to an absolute
|
||||
/// position.
|
||||
pub fn to_absolute(relative: &Location, base: &Location) -> Location {
|
||||
|
||||
@@ -54,7 +54,7 @@ pub struct Scope<'a> {
|
||||
pub id: usize,
|
||||
pub kind: ScopeKind<'a>,
|
||||
pub import_starred: bool,
|
||||
pub values: FnvHashMap<String, Binding>,
|
||||
pub values: FnvHashMap<&'a str, Binding>,
|
||||
}
|
||||
|
||||
impl<'a> Scope<'a> {
|
||||
@@ -86,7 +86,7 @@ pub enum BindingKind {
|
||||
Definition,
|
||||
Export(Vec<String>),
|
||||
FutureImportation,
|
||||
StarImportation,
|
||||
StarImportation(Option<usize>, Option<String>),
|
||||
Importation(String, String, BindingContext),
|
||||
FromImportation(String, String, BindingContext),
|
||||
SubmoduleImportation(String, String, BindingContext),
|
||||
|
||||
337
src/check_ast.rs
337
src/check_ast.rs
@@ -222,7 +222,7 @@ where
|
||||
for name in names {
|
||||
for scope in self.scopes.iter_mut().skip(GLOBAL_SCOPE_INDEX + 1) {
|
||||
scope.values.insert(
|
||||
name.to_string(),
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::Assignment,
|
||||
used: Some((global_scope_id, Range::from_located(stmt))),
|
||||
@@ -309,6 +309,8 @@ where
|
||||
name,
|
||||
decorator_list,
|
||||
args,
|
||||
&self.from_imports,
|
||||
&self.import_aliases,
|
||||
&self.settings.pep8_naming,
|
||||
)
|
||||
{
|
||||
@@ -322,6 +324,8 @@ where
|
||||
name,
|
||||
decorator_list,
|
||||
args,
|
||||
&self.from_imports,
|
||||
&self.import_aliases,
|
||||
&self.settings.pep8_naming,
|
||||
) {
|
||||
self.add_check(check);
|
||||
@@ -397,7 +401,7 @@ where
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
self.add_binding(
|
||||
name.to_string(),
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::Definition,
|
||||
used: None,
|
||||
@@ -502,7 +506,7 @@ where
|
||||
let name = alias.node.name.split('.').next().unwrap();
|
||||
let full_name = &alias.node.name;
|
||||
self.add_binding(
|
||||
name.to_string(),
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::SubmoduleImportation(
|
||||
name.to_string(),
|
||||
@@ -524,7 +528,7 @@ where
|
||||
let name = alias.node.asname.as_ref().unwrap_or(&alias.node.name);
|
||||
let full_name = &alias.node.name;
|
||||
self.add_binding(
|
||||
name.to_string(),
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::Importation(
|
||||
name.to_string(),
|
||||
@@ -657,7 +661,7 @@ where
|
||||
if let Some("__future__") = module.as_deref() {
|
||||
let name = alias.node.asname.as_ref().unwrap_or(&alias.node.name);
|
||||
self.add_binding(
|
||||
name.to_string(),
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::FutureImportation,
|
||||
// Always mark `__future__` imports as used.
|
||||
@@ -694,16 +698,10 @@ where
|
||||
));
|
||||
}
|
||||
} else if alias.node.name == "*" {
|
||||
let module_name = format!(
|
||||
"{}{}",
|
||||
".".repeat(level.unwrap_or_default()),
|
||||
module.clone().unwrap_or_else(|| "module".to_string()),
|
||||
);
|
||||
|
||||
self.add_binding(
|
||||
module_name.to_string(),
|
||||
"*",
|
||||
Binding {
|
||||
kind: BindingKind::StarImportation,
|
||||
kind: BindingKind::StarImportation(*level, module.clone()),
|
||||
used: None,
|
||||
range: Range::from_located(stmt),
|
||||
},
|
||||
@@ -714,7 +712,10 @@ where
|
||||
[*(self.scope_stack.last().expect("No current scope found."))];
|
||||
if !matches!(scope.kind, ScopeKind::Module) {
|
||||
self.add_check(Check::new(
|
||||
CheckKind::ImportStarNotPermitted(module_name.to_string()),
|
||||
CheckKind::ImportStarNotPermitted(helpers::format_import_from(
|
||||
level.as_ref(),
|
||||
module.as_ref(),
|
||||
)),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
@@ -722,7 +723,10 @@ where
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::F403) {
|
||||
self.add_check(Check::new(
|
||||
CheckKind::ImportStarUsed(module_name.to_string()),
|
||||
CheckKind::ImportStarUsed(helpers::format_import_from(
|
||||
level.as_ref(),
|
||||
module.as_ref(),
|
||||
)),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
@@ -746,7 +750,7 @@ where
|
||||
Some(parent) => format!("{}.{}", parent, alias.node.name),
|
||||
};
|
||||
self.add_binding(
|
||||
name.to_string(),
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::FromImportation(
|
||||
name.to_string(),
|
||||
@@ -862,7 +866,12 @@ where
|
||||
pyflakes::plugins::assert_tuple(self, stmt, test);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::B011) {
|
||||
flake8_bugbear::plugins::assert_false(self, stmt, test, msg);
|
||||
flake8_bugbear::plugins::assert_false(
|
||||
self,
|
||||
stmt,
|
||||
test,
|
||||
msg.as_ref().map(|expr| expr.deref()),
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::S101) {
|
||||
self.add_check(flake8_bandit::plugins::assert_used(stmt));
|
||||
@@ -900,10 +909,12 @@ where
|
||||
}
|
||||
StmtKind::Assign { targets, value, .. } => {
|
||||
if self.settings.enabled.contains(&CheckCode::E731) {
|
||||
if let Some(check) =
|
||||
pycodestyle::checks::do_not_assign_lambda(value, Range::from_located(stmt))
|
||||
{
|
||||
self.add_check(check);
|
||||
if let [target] = &targets[..] {
|
||||
if let Some(check) =
|
||||
pycodestyle::checks::do_not_assign_lambda(target, value, stmt)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::U001) {
|
||||
@@ -920,13 +931,12 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
StmtKind::AnnAssign { value, .. } => {
|
||||
StmtKind::AnnAssign { target, value, .. } => {
|
||||
if self.settings.enabled.contains(&CheckCode::E731) {
|
||||
if let Some(value) = value {
|
||||
if let Some(check) = pycodestyle::checks::do_not_assign_lambda(
|
||||
value,
|
||||
Range::from_located(stmt),
|
||||
) {
|
||||
if let Some(check) =
|
||||
pycodestyle::checks::do_not_assign_lambda(target, value, stmt)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
@@ -1017,7 +1027,7 @@ where
|
||||
if let StmtKind::ClassDef { name, .. } = &stmt.node {
|
||||
self.pop_scope();
|
||||
self.add_binding(
|
||||
name.to_string(),
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::ClassDefinition,
|
||||
used: None,
|
||||
@@ -1130,7 +1140,7 @@ where
|
||||
|
||||
self.check_builtin_shadowing(id, Range::from_located(expr), true);
|
||||
|
||||
self.handle_node_store(expr, self.current_parent());
|
||||
self.handle_node_store(id, expr, self.current_parent());
|
||||
}
|
||||
ExprContext::Del => self.handle_node_delete(expr),
|
||||
}
|
||||
@@ -1860,8 +1870,9 @@ where
|
||||
false,
|
||||
);
|
||||
|
||||
if self.current_scope().values.contains_key(name) {
|
||||
if self.current_scope().values.contains_key(&name.as_str()) {
|
||||
self.handle_node_store(
|
||||
name,
|
||||
&Expr::new(
|
||||
excepthandler.location,
|
||||
excepthandler.end_location.unwrap(),
|
||||
@@ -1874,8 +1885,9 @@ where
|
||||
);
|
||||
}
|
||||
|
||||
let definition = self.current_scope().values.get(name).cloned();
|
||||
let definition = self.current_scope().values.get(&name.as_str()).cloned();
|
||||
self.handle_node_store(
|
||||
name,
|
||||
&Expr::new(
|
||||
excepthandler.location,
|
||||
excepthandler.end_location.unwrap(),
|
||||
@@ -1892,7 +1904,7 @@ where
|
||||
if let Some(binding) = {
|
||||
let scope = &mut self.scopes
|
||||
[*(self.scope_stack.last().expect("No current scope found."))];
|
||||
&scope.values.remove(name)
|
||||
&scope.values.remove(&name.as_str())
|
||||
} {
|
||||
if binding.used.is_none() {
|
||||
if self.settings.enabled.contains(&CheckCode::F841) {
|
||||
@@ -1907,7 +1919,7 @@ where
|
||||
if let Some(binding) = definition {
|
||||
let scope = &mut self.scopes
|
||||
[*(self.scope_stack.last().expect("No current scope found."))];
|
||||
scope.values.insert(name.to_string(), binding);
|
||||
scope.values.insert(name, binding);
|
||||
}
|
||||
}
|
||||
None => walk_excepthandler(self, excepthandler),
|
||||
@@ -1951,7 +1963,7 @@ where
|
||||
// Bind, but intentionally avoid walking the annotation, as we handle it
|
||||
// upstream.
|
||||
self.add_binding(
|
||||
arg.node.arg.to_string(),
|
||||
&arg.node.arg,
|
||||
Binding {
|
||||
kind: BindingKind::Argument,
|
||||
used: None,
|
||||
@@ -2016,7 +2028,7 @@ fn try_mark_used(scope: &mut Scope, scope_id: usize, id: &str, expr: &Expr) -> b
|
||||
};
|
||||
|
||||
// Mark the sub-importation as used.
|
||||
if let Some(binding) = scope.values.get_mut(&alias) {
|
||||
if let Some(binding) = scope.values.get_mut(alias.as_str()) {
|
||||
binding.used = Some((scope_id, Range::from_located(expr)));
|
||||
}
|
||||
true
|
||||
@@ -2052,7 +2064,7 @@ impl<'a> Checker<'a> {
|
||||
|
||||
for builtin in BUILTINS {
|
||||
scope.values.insert(
|
||||
(*builtin).to_string(),
|
||||
builtin,
|
||||
Binding {
|
||||
kind: BindingKind::Builtin,
|
||||
range: Default::default(),
|
||||
@@ -2062,7 +2074,7 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
for builtin in MAGIC_GLOBALS {
|
||||
scope.values.insert(
|
||||
(*builtin).to_string(),
|
||||
builtin,
|
||||
Binding {
|
||||
kind: BindingKind::Builtin,
|
||||
range: Default::default(),
|
||||
@@ -2090,23 +2102,26 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_binding(&mut self, name: String, binding: Binding) {
|
||||
fn add_binding<'b>(&mut self, name: &'b str, binding: Binding)
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
if self.settings.enabled.contains(&CheckCode::F402) {
|
||||
let scope = &self.scopes[*(self.scope_stack.last().expect("No current scope found."))];
|
||||
if let Some(existing) = scope.values.get(&name) {
|
||||
if matches!(binding.kind, BindingKind::LoopVar)
|
||||
&& matches!(
|
||||
existing.kind,
|
||||
BindingKind::Importation(_, _, _)
|
||||
| BindingKind::FromImportation(_, _, _)
|
||||
| BindingKind::SubmoduleImportation(_, _, _)
|
||||
| BindingKind::StarImportation
|
||||
BindingKind::Importation(..)
|
||||
| BindingKind::FromImportation(..)
|
||||
| BindingKind::SubmoduleImportation(..)
|
||||
| BindingKind::StarImportation(..)
|
||||
| BindingKind::FutureImportation
|
||||
)
|
||||
{
|
||||
self.add_check(Check::new(
|
||||
CheckKind::ImportShadowedByLoopVar(
|
||||
name.clone(),
|
||||
name.to_string(),
|
||||
existing.range.location.row(),
|
||||
),
|
||||
binding.range,
|
||||
@@ -2164,16 +2179,19 @@ impl<'a> Checker<'a> {
|
||||
let mut from_list = vec![];
|
||||
for scope_index in self.scope_stack.iter().rev() {
|
||||
let scope = &self.scopes[*scope_index];
|
||||
for (name, binding) in scope.values.iter() {
|
||||
if matches!(binding.kind, BindingKind::StarImportation) {
|
||||
from_list.push(name.to_string());
|
||||
for binding in scope.values.values() {
|
||||
if let BindingKind::StarImportation(level, module) = &binding.kind {
|
||||
from_list.push(helpers::format_import_from(
|
||||
level.as_ref(),
|
||||
module.as_ref(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
from_list.sort();
|
||||
|
||||
self.add_check(Check::new(
|
||||
CheckKind::ImportStarUsage(id.clone(), from_list),
|
||||
CheckKind::ImportStarUsage(id.to_string(), from_list),
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
@@ -2204,113 +2222,112 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_node_store(&mut self, expr: &Expr, parent: &Stmt) {
|
||||
if let ExprKind::Name { id, .. } = &expr.node {
|
||||
if self.settings.enabled.contains(&CheckCode::F823) {
|
||||
let scopes: Vec<&Scope> = self
|
||||
.scope_stack
|
||||
.iter()
|
||||
.map(|index| &self.scopes[*index])
|
||||
.collect();
|
||||
if let Some(check) = pyflakes::checks::undefined_local(&scopes, id) {
|
||||
self.add_check(check);
|
||||
}
|
||||
fn handle_node_store<'b>(&mut self, id: &'b str, expr: &Expr, parent: &Stmt)
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
if self.settings.enabled.contains(&CheckCode::F823) {
|
||||
let scopes: Vec<&Scope> = self
|
||||
.scope_stack
|
||||
.iter()
|
||||
.map(|index| &self.scopes[*index])
|
||||
.collect();
|
||||
if let Some(check) = pyflakes::checks::undefined_local(&scopes, id) {
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::N806) {
|
||||
if matches!(self.current_scope().kind, ScopeKind::Function(..)) {
|
||||
pep8_naming::plugins::non_lowercase_variable_in_function(self, expr, parent, id)
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::N806) {
|
||||
if matches!(self.current_scope().kind, ScopeKind::Function(..)) {
|
||||
pep8_naming::plugins::non_lowercase_variable_in_function(self, expr, parent, id)
|
||||
}
|
||||
}
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::N815) {
|
||||
if matches!(self.current_scope().kind, ScopeKind::Class(..)) {
|
||||
pep8_naming::plugins::mixed_case_variable_in_class_scope(self, expr, parent, id)
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::N815) {
|
||||
if matches!(self.current_scope().kind, ScopeKind::Class(..)) {
|
||||
pep8_naming::plugins::mixed_case_variable_in_class_scope(self, expr, parent, id)
|
||||
}
|
||||
}
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::N816) {
|
||||
if matches!(self.current_scope().kind, ScopeKind::Module) {
|
||||
pep8_naming::plugins::mixed_case_variable_in_global_scope(
|
||||
self, expr, parent, id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(parent.node, StmtKind::AnnAssign { value: None, .. }) {
|
||||
self.add_binding(
|
||||
id.to_string(),
|
||||
Binding {
|
||||
kind: BindingKind::Annotation,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(charlie): Include comprehensions here.
|
||||
if matches!(
|
||||
parent.node,
|
||||
StmtKind::For { .. } | StmtKind::AsyncFor { .. }
|
||||
) {
|
||||
self.add_binding(
|
||||
id.to_string(),
|
||||
Binding {
|
||||
kind: BindingKind::LoopVar,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if operations::is_unpacking_assignment(parent) {
|
||||
self.add_binding(
|
||||
id.to_string(),
|
||||
Binding {
|
||||
kind: BindingKind::Binding,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let current =
|
||||
&self.scopes[*(self.scope_stack.last().expect("No current scope found."))];
|
||||
if id == "__all__"
|
||||
&& matches!(current.kind, ScopeKind::Module)
|
||||
&& matches!(
|
||||
parent.node,
|
||||
StmtKind::Assign { .. }
|
||||
| StmtKind::AugAssign { .. }
|
||||
| StmtKind::AnnAssign { .. }
|
||||
)
|
||||
{
|
||||
self.add_binding(
|
||||
id.to_string(),
|
||||
Binding {
|
||||
kind: BindingKind::Export(extract_all_names(parent, current)),
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
},
|
||||
);
|
||||
return;
|
||||
if self.settings.enabled.contains(&CheckCode::N816) {
|
||||
if matches!(self.current_scope().kind, ScopeKind::Module) {
|
||||
pep8_naming::plugins::mixed_case_variable_in_global_scope(self, expr, parent, id)
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(parent.node, StmtKind::AnnAssign { value: None, .. }) {
|
||||
self.add_binding(
|
||||
id.to_string(),
|
||||
id,
|
||||
Binding {
|
||||
kind: BindingKind::Assignment,
|
||||
kind: BindingKind::Annotation,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(charlie): Include comprehensions here.
|
||||
if matches!(
|
||||
parent.node,
|
||||
StmtKind::For { .. } | StmtKind::AsyncFor { .. }
|
||||
) {
|
||||
self.add_binding(
|
||||
id,
|
||||
Binding {
|
||||
kind: BindingKind::LoopVar,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if operations::is_unpacking_assignment(parent) {
|
||||
self.add_binding(
|
||||
id,
|
||||
Binding {
|
||||
kind: BindingKind::Binding,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let current = &self.scopes[*(self.scope_stack.last().expect("No current scope found."))];
|
||||
if id == "__all__"
|
||||
&& matches!(current.kind, ScopeKind::Module)
|
||||
&& matches!(
|
||||
parent.node,
|
||||
StmtKind::Assign { .. } | StmtKind::AugAssign { .. } | StmtKind::AnnAssign { .. }
|
||||
)
|
||||
{
|
||||
self.add_binding(
|
||||
id,
|
||||
Binding {
|
||||
kind: BindingKind::Export(extract_all_names(parent, current)),
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
self.add_binding(
|
||||
id,
|
||||
Binding {
|
||||
kind: BindingKind::Assignment,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_node_delete(&mut self, expr: &Expr) {
|
||||
fn handle_node_delete<'b>(&mut self, expr: &'b Expr)
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
if let ExprKind::Name { id, .. } = &expr.node {
|
||||
if operations::on_conditional_branch(
|
||||
&mut self
|
||||
@@ -2324,10 +2341,11 @@ impl<'a> Checker<'a> {
|
||||
|
||||
let scope =
|
||||
&mut self.scopes[*(self.scope_stack.last().expect("No current scope found."))];
|
||||
if scope.values.remove(id).is_none() && self.settings.enabled.contains(&CheckCode::F821)
|
||||
if scope.values.remove(&id.as_str()).is_none()
|
||||
&& self.settings.enabled.contains(&CheckCode::F821)
|
||||
{
|
||||
self.add_check(Check::new(
|
||||
CheckKind::UndefinedName(id.clone()),
|
||||
CheckKind::UndefinedName(id.to_string()),
|
||||
Range::from_located(expr),
|
||||
))
|
||||
}
|
||||
@@ -2459,16 +2477,19 @@ impl<'a> Checker<'a> {
|
||||
|
||||
let mut checks: Vec<Check> = vec![];
|
||||
for scope in self.dead_scopes.iter().map(|index| &self.scopes[*index]) {
|
||||
let all_binding = scope.values.get("__all__");
|
||||
let all_names = all_binding.and_then(|binding| match &binding.kind {
|
||||
BindingKind::Export(names) => Some(names),
|
||||
_ => None,
|
||||
});
|
||||
let all_binding: Option<&Binding> = scope.values.get("__all__");
|
||||
let all_names: Option<Vec<&str>> =
|
||||
all_binding.and_then(|binding| match &binding.kind {
|
||||
BindingKind::Export(names) => {
|
||||
Some(names.iter().map(|name| name.as_str()).collect())
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::F822) {
|
||||
if !scope.import_starred && !self.path.ends_with("__init__.py") {
|
||||
if let Some(all_binding) = all_binding {
|
||||
if let Some(names) = all_names {
|
||||
if let Some(names) = &all_names {
|
||||
for name in names {
|
||||
if !scope.values.contains_key(name) {
|
||||
checks.push(Check::new(
|
||||
@@ -2485,11 +2506,14 @@ impl<'a> Checker<'a> {
|
||||
if self.settings.enabled.contains(&CheckCode::F405) {
|
||||
if scope.import_starred {
|
||||
if let Some(all_binding) = all_binding {
|
||||
if let Some(names) = all_names {
|
||||
if let Some(names) = &all_names {
|
||||
let mut from_list = vec![];
|
||||
for (name, binding) in scope.values.iter() {
|
||||
if matches!(binding.kind, BindingKind::StarImportation) {
|
||||
from_list.push(name.to_string());
|
||||
for binding in scope.values.values() {
|
||||
if let BindingKind::StarImportation(level, module) = &binding.kind {
|
||||
from_list.push(helpers::format_import_from(
|
||||
level.as_ref(),
|
||||
module.as_ref(),
|
||||
));
|
||||
}
|
||||
}
|
||||
from_list.sort();
|
||||
@@ -2497,7 +2521,10 @@ impl<'a> Checker<'a> {
|
||||
for name in names {
|
||||
if !scope.values.contains_key(name) {
|
||||
checks.push(Check::new(
|
||||
CheckKind::ImportStarUsage(name.clone(), from_list.clone()),
|
||||
CheckKind::ImportStarUsage(
|
||||
name.to_string(),
|
||||
from_list.clone(),
|
||||
),
|
||||
all_binding.range,
|
||||
));
|
||||
}
|
||||
@@ -2514,8 +2541,18 @@ impl<'a> Checker<'a> {
|
||||
BTreeMap::new();
|
||||
|
||||
for (name, binding) in scope.values.iter() {
|
||||
if !matches!(
|
||||
binding.kind,
|
||||
BindingKind::Importation(..)
|
||||
| BindingKind::SubmoduleImportation(..)
|
||||
| BindingKind::FromImportation(..)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let used = binding.used.is_some()
|
||||
|| all_names
|
||||
.as_ref()
|
||||
.map(|names| names.contains(name))
|
||||
.unwrap_or_default();
|
||||
|
||||
@@ -2542,7 +2579,7 @@ impl<'a> Checker<'a> {
|
||||
.or_default()
|
||||
.push(full_name);
|
||||
}
|
||||
_ => {}
|
||||
_ => unreachable!("Already filtered on BindingKind."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +58,7 @@ pub fn check_lines(
|
||||
// Grab the noqa (logical) line number for the current (physical) line.
|
||||
// If there are newlines at the end of the file, they won't be represented in
|
||||
// `noqa_line_for`, so fallback to the current line.
|
||||
let noqa_lineno = noqa_line_for
|
||||
.get(&lineno)
|
||||
.map(|lineno| lineno - 1)
|
||||
.unwrap_or(lineno);
|
||||
let noqa_lineno = noqa_line_for.get(&(lineno + 1)).unwrap_or(&(lineno + 1)) - 1;
|
||||
|
||||
// Enforce unnecessary coding comments (U009).
|
||||
if enforce_unnecessary_coding_comment {
|
||||
@@ -155,10 +152,7 @@ pub fn check_lines(
|
||||
// want to raise W292 anyway).
|
||||
if let Some(line) = lines.last() {
|
||||
let lineno = lines.len() - 1;
|
||||
let noqa_lineno = noqa_line_for
|
||||
.get(&lineno)
|
||||
.map(|lineno| lineno - 1)
|
||||
.unwrap_or(lineno);
|
||||
let noqa_lineno = noqa_line_for.get(&(lineno + 1)).unwrap_or(&(lineno + 1)) - 1;
|
||||
|
||||
let noqa = noqa_directives
|
||||
.entry(noqa_lineno)
|
||||
|
||||
@@ -152,7 +152,7 @@ pub fn warn_on(
|
||||
cli_ignore: &[CheckCodePrefix],
|
||||
cli_extend_ignore: &[CheckCodePrefix],
|
||||
pyproject_configuration: &Configuration,
|
||||
pyproject_path: &Option<PathBuf>,
|
||||
pyproject_path: Option<&PathBuf>,
|
||||
) {
|
||||
for code in codes {
|
||||
if !cli_ignore.is_empty() {
|
||||
@@ -192,7 +192,7 @@ pub fn warn_on(
|
||||
/// Convert a list of `PatternPrefixPair` structs to `PerFileIgnore`.
|
||||
pub fn collect_per_file_ignores(
|
||||
pairs: Vec<PatternPrefixPair>,
|
||||
project_root: &Option<PathBuf>,
|
||||
project_root: Option<&PathBuf>,
|
||||
) -> Vec<PerFileIgnore> {
|
||||
let mut per_file_ignores: FnvHashMap<String, Vec<CheckCodePrefix>> = FnvHashMap::default();
|
||||
for pair in pairs {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustpython_ast::{Arguments, Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
@@ -11,7 +13,7 @@ use crate::{visibility, Check};
|
||||
|
||||
#[derive(Default)]
|
||||
struct ReturnStatementVisitor<'a> {
|
||||
returns: Vec<&'a Option<Box<Expr>>>,
|
||||
returns: Vec<Option<&'a Expr>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Visitor<'b> for ReturnStatementVisitor<'a>
|
||||
@@ -23,7 +25,9 @@ where
|
||||
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => {
|
||||
// No recurse.
|
||||
}
|
||||
StmtKind::Return { value } => self.returns.push(value),
|
||||
StmtKind::Return { value } => {
|
||||
self.returns.push(value.as_ref().map(|expr| expr.deref()))
|
||||
}
|
||||
_ => visitor::walk_stmt(self, stmt),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::code_gen::SourceGenerator;
|
||||
|
||||
fn assertion_error(msg: &Option<Box<Expr>>) -> Stmt {
|
||||
fn assertion_error(msg: Option<&Expr>) -> Stmt {
|
||||
Stmt::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
@@ -24,7 +24,7 @@ fn assertion_error(msg: &Option<Box<Expr>>) -> Stmt {
|
||||
},
|
||||
)),
|
||||
args: if let Some(msg) = msg {
|
||||
vec![*msg.clone()]
|
||||
vec![msg.clone()]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
@@ -36,7 +36,7 @@ fn assertion_error(msg: &Option<Box<Expr>>) -> Stmt {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: &Option<Box<Expr>>) {
|
||||
pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option<&Expr>) {
|
||||
if let ExprKind::Constant {
|
||||
value: Constant::Bool(false),
|
||||
..
|
||||
|
||||
@@ -2,7 +2,7 @@ use fnv::{FnvHashMap, FnvHashSet};
|
||||
use rustpython_ast::{Arguments, Constant, Expr, ExprKind};
|
||||
|
||||
use crate::ast::helpers::{
|
||||
collect_call_paths, compose_call_path, dealias_call_path, match_call_path,
|
||||
collect_call_paths, compose_call_path, dealias_call_path, match_call_path, to_module_and_member,
|
||||
};
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::visitor;
|
||||
@@ -104,14 +104,7 @@ pub fn function_call_argument_default(checker: &mut Checker, arguments: &Argumen
|
||||
.flake8_bugbear
|
||||
.extend_immutable_calls
|
||||
.iter()
|
||||
.map(|s| {
|
||||
let s = s.as_str();
|
||||
if let Some(index) = s.rfind('.') {
|
||||
(&s[..index], &s[index + 1..])
|
||||
} else {
|
||||
("", s)
|
||||
}
|
||||
})
|
||||
.map(|target| to_module_and_member(target))
|
||||
.collect();
|
||||
let mut visitor = ArgumentDefaultVisitor {
|
||||
checks: vec![],
|
||||
|
||||
14
src/fs.rs
14
src/fs.rs
@@ -202,7 +202,7 @@ mod tests {
|
||||
let path = Path::new("foo").absolutize_from(project_root).unwrap();
|
||||
let exclude = vec![FilePattern::from_user(
|
||||
"foo",
|
||||
&Some(project_root.to_path_buf()),
|
||||
Some(&project_root.to_path_buf()),
|
||||
)];
|
||||
let (file_path, file_basename) = extract_path_names(&path)?;
|
||||
assert!(is_excluded(file_path, file_basename, exclude.iter()));
|
||||
@@ -210,7 +210,7 @@ mod tests {
|
||||
let path = Path::new("foo/bar").absolutize_from(project_root).unwrap();
|
||||
let exclude = vec![FilePattern::from_user(
|
||||
"bar",
|
||||
&Some(project_root.to_path_buf()),
|
||||
Some(&project_root.to_path_buf()),
|
||||
)];
|
||||
let (file_path, file_basename) = extract_path_names(&path)?;
|
||||
assert!(is_excluded(file_path, file_basename, exclude.iter()));
|
||||
@@ -220,7 +220,7 @@ mod tests {
|
||||
.unwrap();
|
||||
let exclude = vec![FilePattern::from_user(
|
||||
"baz.py",
|
||||
&Some(project_root.to_path_buf()),
|
||||
Some(&project_root.to_path_buf()),
|
||||
)];
|
||||
let (file_path, file_basename) = extract_path_names(&path)?;
|
||||
assert!(is_excluded(file_path, file_basename, exclude.iter()));
|
||||
@@ -228,7 +228,7 @@ mod tests {
|
||||
let path = Path::new("foo/bar").absolutize_from(project_root).unwrap();
|
||||
let exclude = vec![FilePattern::from_user(
|
||||
"foo/bar",
|
||||
&Some(project_root.to_path_buf()),
|
||||
Some(&project_root.to_path_buf()),
|
||||
)];
|
||||
let (file_path, file_basename) = extract_path_names(&path)?;
|
||||
assert!(is_excluded(file_path, file_basename, exclude.iter()));
|
||||
@@ -238,7 +238,7 @@ mod tests {
|
||||
.unwrap();
|
||||
let exclude = vec![FilePattern::from_user(
|
||||
"foo/bar/baz.py",
|
||||
&Some(project_root.to_path_buf()),
|
||||
Some(&project_root.to_path_buf()),
|
||||
)];
|
||||
let (file_path, file_basename) = extract_path_names(&path)?;
|
||||
assert!(is_excluded(file_path, file_basename, exclude.iter()));
|
||||
@@ -248,7 +248,7 @@ mod tests {
|
||||
.unwrap();
|
||||
let exclude = vec![FilePattern::from_user(
|
||||
"foo/bar/*.py",
|
||||
&Some(project_root.to_path_buf()),
|
||||
Some(&project_root.to_path_buf()),
|
||||
)];
|
||||
let (file_path, file_basename) = extract_path_names(&path)?;
|
||||
assert!(is_excluded(file_path, file_basename, exclude.iter()));
|
||||
@@ -258,7 +258,7 @@ mod tests {
|
||||
.unwrap();
|
||||
let exclude = vec![FilePattern::from_user(
|
||||
"baz",
|
||||
&Some(project_root.to_path_buf()),
|
||||
Some(&project_root.to_path_buf()),
|
||||
)];
|
||||
let (file_path, file_basename) = extract_path_names(&path)?;
|
||||
assert!(!is_excluded(file_path, file_basename, exclude.iter()));
|
||||
|
||||
@@ -15,13 +15,13 @@ pub enum ImportType {
|
||||
|
||||
pub fn categorize(
|
||||
module_base: &str,
|
||||
level: &Option<usize>,
|
||||
level: Option<&usize>,
|
||||
src: &[PathBuf],
|
||||
known_first_party: &BTreeSet<String>,
|
||||
known_third_party: &BTreeSet<String>,
|
||||
extra_standard_library: &BTreeSet<String>,
|
||||
) -> ImportType {
|
||||
if level.map(|level| level > 0).unwrap_or(false) {
|
||||
if level.map(|level| *level > 0).unwrap_or(false) {
|
||||
ImportType::LocalFolder
|
||||
} else if known_first_party.contains(module_base) {
|
||||
ImportType::FirstParty
|
||||
|
||||
@@ -25,7 +25,7 @@ mod types;
|
||||
#[derive(Debug)]
|
||||
pub struct AnnotatedAliasData<'a> {
|
||||
pub name: &'a str,
|
||||
pub asname: &'a Option<String>,
|
||||
pub asname: Option<&'a String>,
|
||||
pub atop: Vec<Comment<'a>>,
|
||||
pub inline: Vec<Comment<'a>>,
|
||||
}
|
||||
@@ -37,9 +37,9 @@ pub enum AnnotatedImport<'a> {
|
||||
inline: Vec<Comment<'a>>,
|
||||
},
|
||||
ImportFrom {
|
||||
module: &'a Option<String>,
|
||||
module: Option<&'a String>,
|
||||
names: Vec<AnnotatedAliasData<'a>>,
|
||||
level: &'a Option<usize>,
|
||||
level: Option<&'a usize>,
|
||||
atop: Vec<Comment<'a>>,
|
||||
inline: Vec<Comment<'a>>,
|
||||
},
|
||||
@@ -75,7 +75,7 @@ fn annotate_imports<'a>(
|
||||
.iter()
|
||||
.map(|alias| AliasData {
|
||||
name: &alias.node.name,
|
||||
asname: &alias.node.asname,
|
||||
asname: alias.node.asname.as_ref(),
|
||||
})
|
||||
.collect(),
|
||||
atop,
|
||||
@@ -124,16 +124,16 @@ fn annotate_imports<'a>(
|
||||
|
||||
aliases.push(AnnotatedAliasData {
|
||||
name: &alias.node.name,
|
||||
asname: &alias.node.asname,
|
||||
asname: alias.node.asname.as_ref(),
|
||||
atop: alias_atop,
|
||||
inline: alias_inline,
|
||||
})
|
||||
}
|
||||
|
||||
annotated.push(AnnotatedImport::ImportFrom {
|
||||
module,
|
||||
module: module.as_ref(),
|
||||
names: aliases,
|
||||
level,
|
||||
level: level.as_ref(),
|
||||
atop,
|
||||
inline,
|
||||
});
|
||||
@@ -278,7 +278,7 @@ fn categorize_imports<'a>(
|
||||
for (alias, comments) in block.import {
|
||||
let import_type = categorize(
|
||||
&alias.module_base(),
|
||||
&None,
|
||||
None,
|
||||
src,
|
||||
known_first_party,
|
||||
known_third_party,
|
||||
@@ -384,7 +384,7 @@ fn sort_imports(block: ImportBlock) -> OrderedImportBlock {
|
||||
import_from
|
||||
.module
|
||||
.as_ref()
|
||||
.map(|module| module_key(module, &None)),
|
||||
.map(|module| module_key(module, None)),
|
||||
aliases
|
||||
.first()
|
||||
.map(|(alias, _)| member_key(alias.name, alias.asname)),
|
||||
|
||||
@@ -10,15 +10,15 @@ pub enum Prefix {
|
||||
|
||||
pub fn module_key<'a>(
|
||||
name: &'a str,
|
||||
asname: &'a Option<String>,
|
||||
) -> (String, &'a str, &'a Option<String>) {
|
||||
asname: Option<&'a String>,
|
||||
) -> (String, &'a str, Option<&'a String>) {
|
||||
(name.to_lowercase(), name, asname)
|
||||
}
|
||||
|
||||
pub fn member_key<'a>(
|
||||
name: &'a str,
|
||||
asname: &'a Option<String>,
|
||||
) -> (Prefix, String, &'a Option<String>) {
|
||||
asname: Option<&'a String>,
|
||||
) -> (Prefix, String, Option<&'a String>) {
|
||||
(
|
||||
if name.len() > 1 && string::is_upper(name) {
|
||||
// Ex) `CONSTANT`
|
||||
|
||||
@@ -2,16 +2,18 @@ use std::borrow::Cow;
|
||||
|
||||
use fnv::FnvHashMap;
|
||||
|
||||
use crate::ast;
|
||||
|
||||
#[derive(Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct ImportFromData<'a> {
|
||||
pub module: &'a Option<String>,
|
||||
pub level: &'a Option<usize>,
|
||||
pub module: Option<&'a String>,
|
||||
pub level: Option<&'a usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct AliasData<'a> {
|
||||
pub name: &'a str,
|
||||
pub asname: &'a Option<String>,
|
||||
pub asname: Option<&'a String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@@ -37,16 +39,7 @@ impl Importable for AliasData<'_> {
|
||||
|
||||
impl Importable for ImportFromData<'_> {
|
||||
fn module_name(&self) -> String {
|
||||
let mut module_name = String::new();
|
||||
if let Some(level) = self.level {
|
||||
if level > &0 {
|
||||
module_name.push_str(&".".repeat(*level));
|
||||
}
|
||||
}
|
||||
if let Some(module) = self.module {
|
||||
module_name.push_str(module);
|
||||
}
|
||||
module_name
|
||||
ast::helpers::format_import_from(self.level, self.module)
|
||||
}
|
||||
|
||||
fn module_base(&self) -> String {
|
||||
|
||||
@@ -64,14 +64,16 @@ pub fn check(path: &Path, contents: &str, autofix: bool) -> Result<Vec<Check>> {
|
||||
Some(path) => debug!("Found project root at: {:?}", path),
|
||||
None => debug!("Unable to identify project root; assuming current directory..."),
|
||||
};
|
||||
let pyproject = pyproject::find_pyproject_toml(&project_root);
|
||||
let pyproject = pyproject::find_pyproject_toml(project_root.as_ref());
|
||||
match &pyproject {
|
||||
Some(path) => debug!("Found pyproject.toml at: {:?}", path),
|
||||
None => debug!("Unable to find pyproject.toml; using default settings..."),
|
||||
};
|
||||
|
||||
let settings =
|
||||
Settings::from_configuration(Configuration::from_pyproject(&pyproject, &project_root)?);
|
||||
let settings = Settings::from_configuration(Configuration::from_pyproject(
|
||||
pyproject.as_ref(),
|
||||
project_root.as_ref(),
|
||||
)?);
|
||||
|
||||
// Tokenize once.
|
||||
let tokens: Vec<LexResult> = tokenize(contents);
|
||||
|
||||
15
src/main.rs
15
src/main.rs
@@ -208,7 +208,7 @@ fn inner_main() -> Result<ExitCode> {
|
||||
};
|
||||
let pyproject = cli
|
||||
.config
|
||||
.or_else(|| pyproject::find_pyproject_toml(&project_root));
|
||||
.or_else(|| pyproject::find_pyproject_toml(project_root.as_ref()));
|
||||
match &pyproject {
|
||||
Some(path) => debug!("Found pyproject.toml at: {:?}", path),
|
||||
None => debug!("Unable to find pyproject.toml; using default settings..."),
|
||||
@@ -218,15 +218,16 @@ fn inner_main() -> Result<ExitCode> {
|
||||
let exclude: Vec<FilePattern> = cli
|
||||
.exclude
|
||||
.iter()
|
||||
.map(|path| FilePattern::from_user(path, &project_root))
|
||||
.map(|path| FilePattern::from_user(path, project_root.as_ref()))
|
||||
.collect();
|
||||
let extend_exclude: Vec<FilePattern> = cli
|
||||
.extend_exclude
|
||||
.iter()
|
||||
.map(|path| FilePattern::from_user(path, &project_root))
|
||||
.map(|path| FilePattern::from_user(path, project_root.as_ref()))
|
||||
.collect();
|
||||
|
||||
let mut configuration = Configuration::from_pyproject(&pyproject, &project_root)?;
|
||||
let mut configuration =
|
||||
Configuration::from_pyproject(pyproject.as_ref(), project_root.as_ref())?;
|
||||
if !exclude.is_empty() {
|
||||
configuration.exclude = exclude;
|
||||
}
|
||||
@@ -235,7 +236,7 @@ fn inner_main() -> Result<ExitCode> {
|
||||
}
|
||||
if !cli.per_file_ignores.is_empty() {
|
||||
configuration.per_file_ignores =
|
||||
collect_per_file_ignores(cli.per_file_ignores, &project_root);
|
||||
collect_per_file_ignores(cli.per_file_ignores, project_root.as_ref());
|
||||
}
|
||||
if !cli.select.is_empty() {
|
||||
warn_on(
|
||||
@@ -244,7 +245,7 @@ fn inner_main() -> Result<ExitCode> {
|
||||
&cli.ignore,
|
||||
&cli.extend_ignore,
|
||||
&configuration,
|
||||
&pyproject,
|
||||
pyproject.as_ref(),
|
||||
);
|
||||
configuration.select = cli.select;
|
||||
}
|
||||
@@ -255,7 +256,7 @@ fn inner_main() -> Result<ExitCode> {
|
||||
&cli.ignore,
|
||||
&cli.extend_ignore,
|
||||
&configuration,
|
||||
&pyproject,
|
||||
pyproject.as_ref(),
|
||||
);
|
||||
configuration.extend_select = cli.extend_select;
|
||||
}
|
||||
|
||||
@@ -72,10 +72,7 @@ fn add_noqa_inner(
|
||||
// Grab the noqa (logical) line number for the current (physical) line.
|
||||
// If there are newlines at the end of the file, they won't be represented in
|
||||
// `noqa_line_for`, so fallback to the current line.
|
||||
let noqa_lineno = noqa_line_for
|
||||
.get(&lineno)
|
||||
.map(|lineno| lineno - 1)
|
||||
.unwrap_or(lineno);
|
||||
let noqa_lineno = noqa_line_for.get(&(lineno + 1)).unwrap_or(&(lineno + 1)) - 1;
|
||||
|
||||
if !codes.is_empty() {
|
||||
let matches = matches_by_line.entry(noqa_lineno).or_default();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use rustpython_ast::{Arguments, Expr, ExprKind, Stmt};
|
||||
|
||||
use crate::ast::types::{Range, Scope, ScopeKind};
|
||||
@@ -58,10 +59,19 @@ pub fn invalid_first_argument_name_for_class_method(
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
args: &Arguments,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
settings: &Settings,
|
||||
) -> Option<Check> {
|
||||
if matches!(
|
||||
helpers::function_type(scope, name, decorator_list, settings),
|
||||
helpers::function_type(
|
||||
scope,
|
||||
name,
|
||||
decorator_list,
|
||||
from_imports,
|
||||
import_aliases,
|
||||
settings,
|
||||
),
|
||||
FunctionType::ClassMethod
|
||||
) {
|
||||
if let Some(arg) = args.args.first() {
|
||||
@@ -82,10 +92,19 @@ pub fn invalid_first_argument_name_for_method(
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
args: &Arguments,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
settings: &Settings,
|
||||
) -> Option<Check> {
|
||||
if matches!(
|
||||
helpers::function_type(scope, name, decorator_list, settings),
|
||||
helpers::function_type(
|
||||
scope,
|
||||
name,
|
||||
decorator_list,
|
||||
from_imports,
|
||||
import_aliases,
|
||||
settings,
|
||||
),
|
||||
FunctionType::Method
|
||||
) {
|
||||
if let Some(arg) = args.args.first() {
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use itertools::Itertools;
|
||||
use rustpython_ast::{Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_ast::{Expr, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::helpers::{collect_call_paths, match_call_path, match_name_or_attr};
|
||||
use crate::ast::helpers::{
|
||||
collect_call_paths, dealias_call_path, match_call_path, to_module_and_member,
|
||||
};
|
||||
use crate::ast::types::{Scope, ScopeKind};
|
||||
use crate::pep8_naming::settings::Settings;
|
||||
use crate::python::string::{is_lower, is_upper};
|
||||
|
||||
const CLASS_METHODS: [&str; 3] = ["__new__", "__init_subclass__", "__class_getitem__"];
|
||||
const METACLASS_BASES: [&str; 2] = ["type", "ABCMeta"];
|
||||
const METACLASS_BASES: [(&str, &str); 2] = [("", "type"), ("abc", "ABCMeta")];
|
||||
|
||||
pub enum FunctionType {
|
||||
Function,
|
||||
@@ -22,35 +24,39 @@ pub fn function_type(
|
||||
scope: &Scope,
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
settings: &Settings,
|
||||
) -> FunctionType {
|
||||
if let ScopeKind::Class(scope) = &scope.kind {
|
||||
// Special-case class method, like `__new__`.
|
||||
if CLASS_METHODS.contains(&name)
|
||||
// The class itself extends a known metaclass, so all methods are class methods.
|
||||
|| scope.bases.iter().any(|expr| {
|
||||
METACLASS_BASES
|
||||
.iter()
|
||||
.any(|target| match_name_or_attr(expr, target))
|
||||
// The class itself extends a known metaclass, so all methods are class methods.
|
||||
let call_path = dealias_call_path(collect_call_paths(expr), import_aliases);
|
||||
METACLASS_BASES.iter().any(|(module, member)| {
|
||||
match_call_path(&call_path, module, member, from_imports)
|
||||
})
|
||||
})
|
||||
// The method is decorated with a class method decorator (like `@classmethod`).
|
||||
|| decorator_list.iter().any(|expr| {
|
||||
if let ExprKind::Name { id, .. } = &expr.node {
|
||||
settings.classmethod_decorators.contains(id)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
// The method is decorated with a class method decorator (like `@classmethod`).
|
||||
let call_path = dealias_call_path(collect_call_paths(expr), import_aliases);
|
||||
settings.classmethod_decorators.iter().any(|decorator| {
|
||||
let (module, member) = to_module_and_member(decorator);
|
||||
match_call_path(&call_path, module, member, from_imports)
|
||||
})
|
||||
})
|
||||
{
|
||||
FunctionType::ClassMethod
|
||||
} else if decorator_list.iter().any(|expr| {
|
||||
if let ExprKind::Name { id, .. } = &expr.node {
|
||||
settings.staticmethod_decorators.contains(id)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
// The method is decorated with a static method decorator (like
|
||||
// `@staticmethod`).
|
||||
let call_path = dealias_call_path(collect_call_paths(expr), import_aliases);
|
||||
settings.staticmethod_decorators.iter().any(|decorator| {
|
||||
let (module, member) = to_module_and_member(decorator);
|
||||
match_call_path(&call_path, module, member, from_imports)
|
||||
})
|
||||
}) {
|
||||
FunctionType::StaticMethod
|
||||
} else {
|
||||
// It's an instance method.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use itertools::izip;
|
||||
use rustpython_ast::Location;
|
||||
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Unaryop};
|
||||
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Stmt, Unaryop};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::checks::{Check, CheckKind, RejectedCmpop};
|
||||
@@ -47,12 +47,16 @@ pub fn ambiguous_function_name(name: &str, location: Range) -> Option<Check> {
|
||||
}
|
||||
|
||||
/// E731
|
||||
pub fn do_not_assign_lambda(value: &Expr, location: Range) -> Option<Check> {
|
||||
if let ExprKind::Lambda { .. } = &value.node {
|
||||
Some(Check::new(CheckKind::DoNotAssignLambda, location))
|
||||
} else {
|
||||
None
|
||||
pub fn do_not_assign_lambda(target: &Expr, value: &Expr, stmt: &Stmt) -> Option<Check> {
|
||||
if let ExprKind::Name { .. } = &target.node {
|
||||
if let ExprKind::Lambda { .. } = &value.node {
|
||||
return Some(Check::new(
|
||||
CheckKind::DoNotAssignLambda,
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// E713, E714
|
||||
|
||||
@@ -64,9 +64,9 @@ pub fn unused_variables(scope: &Scope, dummy_variable_rgx: &Regex) -> Vec<Check>
|
||||
if binding.used.is_none()
|
||||
&& matches!(binding.kind, BindingKind::Assignment)
|
||||
&& !dummy_variable_rgx.is_match(name)
|
||||
&& name != "__tracebackhide__"
|
||||
&& name != "__traceback_info__"
|
||||
&& name != "__traceback_supplement__"
|
||||
&& name != &"__tracebackhide__"
|
||||
&& name != &"__traceback_info__"
|
||||
&& name != &"__traceback_supplement__"
|
||||
{
|
||||
checks.push(Check::new(
|
||||
CheckKind::UnusedVariable(name.to_string()),
|
||||
|
||||
@@ -115,7 +115,7 @@ pub fn useless_object_inheritance(name: &str, bases: &[Expr], scope: &Scope) ->
|
||||
for expr in bases {
|
||||
if let ExprKind::Name { id, .. } = &expr.node {
|
||||
if id == "object" {
|
||||
match scope.values.get(id) {
|
||||
match scope.values.get(&id.as_str()) {
|
||||
None
|
||||
| Some(Binding {
|
||||
kind: BindingKind::Builtin,
|
||||
|
||||
@@ -65,8 +65,8 @@ static DEFAULT_DUMMY_VARIABLE_RGX: Lazy<Regex> =
|
||||
|
||||
impl Configuration {
|
||||
pub fn from_pyproject(
|
||||
pyproject: &Option<PathBuf>,
|
||||
project_root: &Option<PathBuf>,
|
||||
pyproject: Option<&PathBuf>,
|
||||
project_root: Option<&PathBuf>,
|
||||
) -> Result<Self> {
|
||||
let options = load_options(pyproject)?;
|
||||
Ok(Configuration {
|
||||
|
||||
@@ -36,7 +36,7 @@ fn parse_pyproject_toml(path: &Path) -> Result<Pyproject> {
|
||||
toml::from_str(&contents).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn find_pyproject_toml(path: &Option<PathBuf>) -> Option<PathBuf> {
|
||||
pub fn find_pyproject_toml(path: Option<&PathBuf>) -> Option<PathBuf> {
|
||||
if let Some(path) = path {
|
||||
let path_pyproject_toml = path.join("pyproject.toml");
|
||||
if path_pyproject_toml.is_file() {
|
||||
@@ -80,7 +80,7 @@ pub fn find_project_root(sources: &[PathBuf]) -> Option<PathBuf> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn load_options(pyproject: &Option<PathBuf>) -> Result<Options> {
|
||||
pub fn load_options(pyproject: Option<&PathBuf>) -> Result<Options> {
|
||||
match pyproject {
|
||||
Some(pyproject) => Ok(parse_pyproject_toml(pyproject)?
|
||||
.tool
|
||||
@@ -323,7 +323,7 @@ other-attribute = 1
|
||||
assert_eq!(project_root, cwd.join("resources/test/fixtures"));
|
||||
|
||||
let path =
|
||||
find_pyproject_toml(&Some(project_root)).expect("Unable to find pyproject.toml.");
|
||||
find_pyproject_toml(Some(&project_root)).expect("Unable to find pyproject.toml.");
|
||||
assert_eq!(path, cwd.join("resources/test/fixtures/pyproject.toml"));
|
||||
|
||||
let pyproject = parse_pyproject_toml(&path)?;
|
||||
|
||||
@@ -51,7 +51,7 @@ pub enum FilePattern {
|
||||
}
|
||||
|
||||
impl FilePattern {
|
||||
pub fn from_user(pattern: &str, project_root: &Option<PathBuf>) -> Self {
|
||||
pub fn from_user(pattern: &str, project_root: Option<&PathBuf>) -> Self {
|
||||
let path = Path::new(pattern);
|
||||
let absolute_path = match project_root {
|
||||
Some(project_root) => fs::normalize_path_to(path, project_root),
|
||||
@@ -79,7 +79,7 @@ impl PerFileIgnore {
|
||||
pub fn new(
|
||||
pattern: &str,
|
||||
prefixes: &[CheckCodePrefix],
|
||||
project_root: &Option<PathBuf>,
|
||||
project_root: Option<&PathBuf>,
|
||||
) -> Self {
|
||||
let pattern = FilePattern::from_user(pattern, project_root);
|
||||
let codes = BTreeSet::from_iter(prefixes.iter().flat_map(|prefix| prefix.codes()));
|
||||
|
||||
@@ -26,20 +26,4 @@ expression: checks
|
||||
row: 7
|
||||
column: 29
|
||||
fix: ~
|
||||
- kind: DoNotAssignLambda
|
||||
location:
|
||||
row: 12
|
||||
column: 0
|
||||
end_location:
|
||||
row: 12
|
||||
column: 27
|
||||
fix: ~
|
||||
- kind: DoNotAssignLambda
|
||||
location:
|
||||
row: 16
|
||||
column: 0
|
||||
end_location:
|
||||
row: 16
|
||||
column: 25
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,18 +4,34 @@ expression: checks
|
||||
---
|
||||
- kind: InvalidFirstArgumentNameForMethod
|
||||
location:
|
||||
row: 5
|
||||
row: 7
|
||||
column: 19
|
||||
end_location:
|
||||
row: 5
|
||||
row: 7
|
||||
column: 23
|
||||
fix: ~
|
||||
- kind: InvalidFirstArgumentNameForMethod
|
||||
location:
|
||||
row: 10
|
||||
row: 12
|
||||
column: 29
|
||||
end_location:
|
||||
row: 10
|
||||
row: 12
|
||||
column: 33
|
||||
fix: ~
|
||||
- kind: InvalidFirstArgumentNameForMethod
|
||||
location:
|
||||
row: 27
|
||||
column: 14
|
||||
end_location:
|
||||
row: 27
|
||||
column: 17
|
||||
fix: ~
|
||||
- kind: InvalidFirstArgumentNameForMethod
|
||||
location:
|
||||
row: 31
|
||||
column: 14
|
||||
end_location:
|
||||
row: 31
|
||||
column: 17
|
||||
fix: ~
|
||||
|
||||
|
||||
Reference in New Issue
Block a user