mirror of https://github.com/astral-sh/ruff
Move `python` into its own `ruff_python` crate (#2593)
This commit is contained in:
parent
ecc9f5de99
commit
87d0aa5561
|
|
@ -84,6 +84,7 @@ At time of writing, the repository includes the following crates:
|
||||||
- `crates/ruff_cli`: binary crate containing Ruff's command-line interface.
|
- `crates/ruff_cli`: binary crate containing Ruff's command-line interface.
|
||||||
- `crates/ruff_dev`: binary crate containing utilities used in the development of Ruff itself (e.g., `cargo dev generate-all`).
|
- `crates/ruff_dev`: binary crate containing utilities used in the development of Ruff itself (e.g., `cargo dev generate-all`).
|
||||||
- `crates/ruff_macros`: library crate containing macros used by Ruff.
|
- `crates/ruff_macros`: library crate containing macros used by Ruff.
|
||||||
|
- `crates/ruff_python`: library crate implementing Python-specific functionality (e.g., lists of standard library modules by versionb).
|
||||||
- `crates/flake8_to_ruff`: binary crate for generating Ruff configuration from Flake8 configuration.
|
- `crates/flake8_to_ruff`: binary crate for generating Ruff configuration from Flake8 configuration.
|
||||||
|
|
||||||
### Example: Adding a new lint rule
|
### Example: Adding a new lint rule
|
||||||
|
|
|
||||||
|
|
@ -1929,6 +1929,7 @@ dependencies = [
|
||||||
"path-absolutize",
|
"path-absolutize",
|
||||||
"regex",
|
"regex",
|
||||||
"ruff_macros",
|
"ruff_macros",
|
||||||
|
"ruff_python",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustpython-ast",
|
"rustpython-ast",
|
||||||
"rustpython-common",
|
"rustpython-common",
|
||||||
|
|
@ -2018,6 +2019,15 @@ dependencies = [
|
||||||
"textwrap",
|
"textwrap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ruff_python"
|
||||||
|
version = "0.0.241"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
"rustc-hash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-stemmers"
|
name = "rust-stemmers"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ once_cell = { version = "1.16.0" }
|
||||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||||
regex = { version = "1.6.0" }
|
regex = { version = "1.6.0" }
|
||||||
ruff_macros = { version = "0.0.241", path = "../ruff_macros" }
|
ruff_macros = { version = "0.0.241", path = "../ruff_macros" }
|
||||||
|
ruff_python = { version = "0.0.241", path = "../ruff_python" }
|
||||||
rustc-hash = { version = "1.1.0" }
|
rustc-hash = { version = "1.1.0" }
|
||||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "adc23253e4b58980b407ba2760dbe61681d752fc" }
|
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "adc23253e4b58980b407ba2760dbe61681d752fc" }
|
||||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "adc23253e4b58980b407ba2760dbe61681d752fc" }
|
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "adc23253e4b58980b407ba2760dbe61681d752fc" }
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,6 @@ pub mod helpers;
|
||||||
pub mod operations;
|
pub mod operations;
|
||||||
pub mod relocate;
|
pub mod relocate;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
pub mod typing;
|
||||||
pub mod visitor;
|
pub mod visitor;
|
||||||
pub mod whitespace;
|
pub mod whitespace;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
use rustpython_ast::{Expr, ExprKind};
|
||||||
|
|
||||||
|
use ruff_python::typing::{PEP_585_BUILTINS_ELIGIBLE, PEP_593_SUBSCRIPTS, SUBSCRIPTS};
|
||||||
|
|
||||||
|
use crate::ast::types::CallPath;
|
||||||
|
|
||||||
|
pub enum Callable {
|
||||||
|
ForwardRef,
|
||||||
|
Cast,
|
||||||
|
NewType,
|
||||||
|
TypeVar,
|
||||||
|
NamedTuple,
|
||||||
|
TypedDict,
|
||||||
|
MypyExtension,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SubscriptKind {
|
||||||
|
AnnotatedSubscript,
|
||||||
|
PEP593AnnotatedSubscript,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn match_annotated_subscript<'a, F>(
|
||||||
|
expr: &'a Expr,
|
||||||
|
resolve_call_path: F,
|
||||||
|
typing_modules: impl Iterator<Item = &'a str>,
|
||||||
|
) -> Option<SubscriptKind>
|
||||||
|
where
|
||||||
|
F: FnOnce(&'a Expr) -> Option<CallPath<'a>>,
|
||||||
|
{
|
||||||
|
if !matches!(
|
||||||
|
expr.node,
|
||||||
|
ExprKind::Name { .. } | ExprKind::Attribute { .. }
|
||||||
|
) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_call_path(expr).and_then(|call_path| {
|
||||||
|
if SUBSCRIPTS.contains(&call_path.as_slice()) {
|
||||||
|
return Some(SubscriptKind::AnnotatedSubscript);
|
||||||
|
}
|
||||||
|
if PEP_593_SUBSCRIPTS.contains(&call_path.as_slice()) {
|
||||||
|
return Some(SubscriptKind::PEP593AnnotatedSubscript);
|
||||||
|
}
|
||||||
|
|
||||||
|
for module in typing_modules {
|
||||||
|
let module_call_path = module.split('.').collect::<Vec<_>>();
|
||||||
|
if call_path.starts_with(&module_call_path) {
|
||||||
|
for subscript in SUBSCRIPTS.iter() {
|
||||||
|
if call_path.last() == subscript.last() {
|
||||||
|
return Some(SubscriptKind::AnnotatedSubscript);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for subscript in PEP_593_SUBSCRIPTS.iter() {
|
||||||
|
if call_path.last() == subscript.last() {
|
||||||
|
return Some(SubscriptKind::PEP593AnnotatedSubscript);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `Expr` represents a reference to a typing object with a
|
||||||
|
/// PEP 585 built-in.
|
||||||
|
pub fn is_pep585_builtin<'a, F>(expr: &'a Expr, resolve_call_path: F) -> bool
|
||||||
|
where
|
||||||
|
F: FnOnce(&'a Expr) -> Option<CallPath<'a>>,
|
||||||
|
{
|
||||||
|
resolve_call_path(expr).map_or(false, |call_path| {
|
||||||
|
PEP_585_BUILTINS_ELIGIBLE.contains(&call_path.as_slice())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,9 @@ use rustpython_parser::ast::{
|
||||||
use rustpython_parser::parser;
|
use rustpython_parser::parser;
|
||||||
use smallvec::smallvec;
|
use smallvec::smallvec;
|
||||||
|
|
||||||
|
use ruff_python::builtins::{BUILTINS, MAGIC_GLOBALS};
|
||||||
|
use ruff_python::typing::TYPING_EXTENSIONS;
|
||||||
|
|
||||||
use crate::ast::helpers::{binding_range, collect_call_path, extract_handler_names};
|
use crate::ast::helpers::{binding_range, collect_call_path, extract_handler_names};
|
||||||
use crate::ast::operations::{extract_all_names, AllNamesFlags};
|
use crate::ast::operations::{extract_all_names, AllNamesFlags};
|
||||||
use crate::ast::relocate::relocate_expr;
|
use crate::ast::relocate::relocate_expr;
|
||||||
|
|
@ -23,13 +26,11 @@ use crate::ast::types::{
|
||||||
Binding, BindingKind, CallPath, ClassDef, ExecutionContext, FunctionDef, Lambda, Node, Range,
|
Binding, BindingKind, CallPath, ClassDef, ExecutionContext, FunctionDef, Lambda, Node, Range,
|
||||||
RefEquality, Scope, ScopeKind,
|
RefEquality, Scope, ScopeKind,
|
||||||
};
|
};
|
||||||
|
use crate::ast::typing::{match_annotated_subscript, Callable, SubscriptKind};
|
||||||
use crate::ast::visitor::{walk_excepthandler, Visitor};
|
use crate::ast::visitor::{walk_excepthandler, Visitor};
|
||||||
use crate::ast::{branch_detection, cast, helpers, operations, visitor};
|
use crate::ast::{branch_detection, cast, helpers, operations, typing, visitor};
|
||||||
use crate::docstrings::definition::{Definition, DefinitionKind, Docstring, Documentable};
|
use crate::docstrings::definition::{Definition, DefinitionKind, Docstring, Documentable};
|
||||||
use crate::noqa::Directive;
|
use crate::noqa::Directive;
|
||||||
use crate::python::builtins::{BUILTINS, MAGIC_GLOBALS};
|
|
||||||
use crate::python::typing;
|
|
||||||
use crate::python::typing::{Callable, SubscriptKind};
|
|
||||||
use crate::registry::{Diagnostic, Rule};
|
use crate::registry::{Diagnostic, Rule};
|
||||||
use crate::rules::{
|
use crate::rules::{
|
||||||
flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except, flake8_boolean_trap,
|
flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except, flake8_boolean_trap,
|
||||||
|
|
@ -194,7 +195,7 @@ impl<'a> Checker<'a> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if typing::TYPING_EXTENSIONS.contains(target) {
|
if TYPING_EXTENSIONS.contains(target) {
|
||||||
if call_path.as_slice() == ["typing_extensions", target] {
|
if call_path.as_slice() == ["typing_extensions", target] {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -2086,7 +2087,7 @@ where
|
||||||
|| (self.settings.target_version >= PythonVersion::Py37
|
|| (self.settings.target_version >= PythonVersion::Py37
|
||||||
&& self.annotations_future_enabled
|
&& self.annotations_future_enabled
|
||||||
&& self.in_annotation))
|
&& self.in_annotation))
|
||||||
&& typing::is_pep585_builtin(self, expr)
|
&& typing::is_pep585_builtin(expr, |expr| self.resolve_call_path(expr))
|
||||||
{
|
{
|
||||||
pyupgrade::rules::use_pep585_annotation(self, expr);
|
pyupgrade::rules::use_pep585_annotation(self, expr);
|
||||||
}
|
}
|
||||||
|
|
@ -2131,7 +2132,7 @@ where
|
||||||
|| (self.settings.target_version >= PythonVersion::Py37
|
|| (self.settings.target_version >= PythonVersion::Py37
|
||||||
&& self.annotations_future_enabled
|
&& self.annotations_future_enabled
|
||||||
&& self.in_annotation))
|
&& self.in_annotation))
|
||||||
&& typing::is_pep585_builtin(self, expr)
|
&& typing::is_pep585_builtin(expr, |expr| self.resolve_call_path(expr))
|
||||||
{
|
{
|
||||||
pyupgrade::rules::use_pep585_annotation(self, expr);
|
pyupgrade::rules::use_pep585_annotation(self, expr);
|
||||||
}
|
}
|
||||||
|
|
@ -3399,7 +3400,11 @@ where
|
||||||
self.in_subscript = true;
|
self.in_subscript = true;
|
||||||
visitor::walk_expr(self, expr);
|
visitor::walk_expr(self, expr);
|
||||||
} else {
|
} else {
|
||||||
match typing::match_annotated_subscript(self, value) {
|
match match_annotated_subscript(
|
||||||
|
value,
|
||||||
|
|expr| self.resolve_call_path(expr),
|
||||||
|
self.settings.typing_modules.iter().map(String::as_str),
|
||||||
|
) {
|
||||||
Some(subscript) => {
|
Some(subscript) => {
|
||||||
match subscript {
|
match subscript {
|
||||||
// Ex) Optional[int]
|
// Ex) Optional[int]
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ pub mod linter;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
pub mod message;
|
pub mod message;
|
||||||
mod noqa;
|
mod noqa;
|
||||||
mod python;
|
|
||||||
pub mod registry;
|
pub mod registry;
|
||||||
pub mod resolver;
|
pub mod resolver;
|
||||||
mod rule_redirects;
|
mod rule_redirects;
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ use crate::ast::types::Range;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::define_violation;
|
use crate::define_violation;
|
||||||
use crate::fix::Fix;
|
use crate::fix::Fix;
|
||||||
use crate::python::identifiers::{is_identifier, is_mangled_private};
|
|
||||||
use crate::python::keyword::KWLIST;
|
|
||||||
use crate::registry::Diagnostic;
|
use crate::registry::Diagnostic;
|
||||||
use crate::violation::AlwaysAutofixableViolation;
|
use crate::violation::AlwaysAutofixableViolation;
|
||||||
use ruff_macros::derive_message_formats;
|
use ruff_macros::derive_message_formats;
|
||||||
|
use ruff_python::identifiers::{is_identifier, is_mangled_private};
|
||||||
|
use ruff_python::keyword::KWLIST;
|
||||||
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location};
|
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location};
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ use crate::ast::types::Range;
|
||||||
use crate::ast::visitor::Visitor;
|
use crate::ast::visitor::Visitor;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::define_violation;
|
use crate::define_violation;
|
||||||
use crate::python::string::is_lower;
|
|
||||||
use crate::registry::Diagnostic;
|
use crate::registry::Diagnostic;
|
||||||
use crate::violation::Violation;
|
use crate::violation::Violation;
|
||||||
use ruff_macros::derive_message_formats;
|
use ruff_macros::derive_message_formats;
|
||||||
|
use ruff_python::string::is_lower;
|
||||||
use rustpython_ast::{ExprKind, Stmt, StmtKind};
|
use rustpython_ast::{ExprKind, Stmt, StmtKind};
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@ use crate::ast::types::Range;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::define_violation;
|
use crate::define_violation;
|
||||||
use crate::fix::Fix;
|
use crate::fix::Fix;
|
||||||
use crate::python::identifiers::{is_identifier, is_mangled_private};
|
|
||||||
use crate::python::keyword::KWLIST;
|
|
||||||
use crate::registry::Diagnostic;
|
use crate::registry::Diagnostic;
|
||||||
use crate::source_code::Stylist;
|
use crate::source_code::Stylist;
|
||||||
use crate::violation::AlwaysAutofixableViolation;
|
use crate::violation::AlwaysAutofixableViolation;
|
||||||
use ruff_macros::derive_message_formats;
|
use ruff_macros::derive_message_formats;
|
||||||
|
use ruff_python::identifiers::{is_identifier, is_mangled_private};
|
||||||
|
use ruff_python::keyword::KWLIST;
|
||||||
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location, Stmt, StmtKind};
|
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location, Stmt, StmtKind};
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use super::types::ShadowingType;
|
use super::types::ShadowingType;
|
||||||
use crate::ast::types::Range;
|
use crate::ast::types::Range;
|
||||||
use crate::define_violation;
|
use crate::define_violation;
|
||||||
use crate::python::builtins::BUILTINS;
|
|
||||||
use crate::registry::{Diagnostic, DiagnosticKind};
|
use crate::registry::{Diagnostic, DiagnosticKind};
|
||||||
use crate::violation::Violation;
|
use crate::violation::Violation;
|
||||||
use ruff_macros::derive_message_formats;
|
use ruff_macros::derive_message_formats;
|
||||||
|
use ruff_python::builtins::BUILTINS;
|
||||||
use rustpython_ast::Located;
|
use rustpython_ast::Located;
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ use crate::checkers::ast::Checker;
|
||||||
use crate::define_violation;
|
use crate::define_violation;
|
||||||
use crate::fix::Fix;
|
use crate::fix::Fix;
|
||||||
use crate::message::Location;
|
use crate::message::Location;
|
||||||
use crate::python::identifiers::is_identifier;
|
|
||||||
use crate::registry::Diagnostic;
|
use crate::registry::Diagnostic;
|
||||||
use crate::violation::{AlwaysAutofixableViolation, Violation};
|
use crate::violation::{AlwaysAutofixableViolation, Violation};
|
||||||
|
use ruff_python::identifiers::is_identifier;
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
pub struct NoUnnecessaryPass;
|
pub struct NoUnnecessaryPass;
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@ use crate::ast::types::Range;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::cst::matchers::{match_comparison, match_expression};
|
use crate::cst::matchers::{match_comparison, match_expression};
|
||||||
use crate::fix::Fix;
|
use crate::fix::Fix;
|
||||||
use crate::python::string::{self};
|
|
||||||
use crate::registry::Diagnostic;
|
use crate::registry::Diagnostic;
|
||||||
use crate::source_code::{Locator, Stylist};
|
use crate::source_code::{Locator, Stylist};
|
||||||
use crate::violation::{Availability, Violation};
|
use crate::violation::{Availability, Violation};
|
||||||
use crate::{define_violation, AutofixKind};
|
use crate::{define_violation, AutofixKind};
|
||||||
|
use ruff_python::string::{self};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use libcst_native::{Codegen, CodegenState, CompOp};
|
use libcst_native::{Codegen, CodegenState, CompOp};
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,12 @@ use log::debug;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::types::{ImportBlock, Importable};
|
use ruff_python::sys::KNOWN_STANDARD_LIBRARY;
|
||||||
use crate::python::sys::KNOWN_STANDARD_LIBRARY;
|
|
||||||
use crate::settings::types::PythonVersion;
|
use crate::settings::types::PythonVersion;
|
||||||
|
|
||||||
|
use super::types::{ImportBlock, Importable};
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema, Hash,
|
Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema, Hash,
|
||||||
)]
|
)]
|
||||||
|
|
@ -58,7 +60,7 @@ pub fn categorize(
|
||||||
} else if module_base == "__future__" {
|
} else if module_base == "__future__" {
|
||||||
(ImportType::Future, Reason::Future)
|
(ImportType::Future, Reason::Future)
|
||||||
} else if KNOWN_STANDARD_LIBRARY
|
} else if KNOWN_STANDARD_LIBRARY
|
||||||
.get(&target_version)
|
.get(&target_version.as_tuple())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.contains(module_base)
|
.contains(module_base)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use std::collections::BTreeSet;
|
||||||
use super::settings::RelativeImportsOrder;
|
use super::settings::RelativeImportsOrder;
|
||||||
use super::types::EitherImport::{Import, ImportFrom};
|
use super::types::EitherImport::{Import, ImportFrom};
|
||||||
use super::types::{AliasData, EitherImport, ImportFromData};
|
use super::types::{AliasData, EitherImport, ImportFromData};
|
||||||
use crate::python::string;
|
use ruff_python::string;
|
||||||
|
|
||||||
#[derive(PartialOrd, Ord, PartialEq, Eq)]
|
#[derive(PartialOrd, Ord, PartialEq, Eq)]
|
||||||
pub enum Prefix {
|
pub enum Prefix {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use itertools::Itertools;
|
||||||
use rustpython_ast::{Stmt, StmtKind};
|
use rustpython_ast::{Stmt, StmtKind};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::python::string::{is_lower, is_upper};
|
use ruff_python::string::{is_lower, is_upper};
|
||||||
|
|
||||||
pub fn is_camelcase(name: &str) -> bool {
|
pub fn is_camelcase(name: &str) -> bool {
|
||||||
!is_lower(name) && !is_upper(name) && !name.contains('_')
|
!is_lower(name) && !is_upper(name) && !name.contains('_')
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ use crate::ast::helpers::identifier_range;
|
||||||
use crate::ast::types::{Range, Scope, ScopeKind};
|
use crate::ast::types::{Range, Scope, ScopeKind};
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::define_violation;
|
use crate::define_violation;
|
||||||
use crate::python::string::{self};
|
|
||||||
use crate::registry::Diagnostic;
|
use crate::registry::Diagnostic;
|
||||||
use crate::source_code::Locator;
|
use crate::source_code::Locator;
|
||||||
use crate::violation::Violation;
|
use crate::violation::Violation;
|
||||||
use ruff_macros::derive_message_formats;
|
use ruff_macros::derive_message_formats;
|
||||||
|
use ruff_python::string::{self};
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
pub struct InvalidClassName {
|
pub struct InvalidClassName {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ use rustpython_parser::lexer::Tok;
|
||||||
use crate::ast::types::Range;
|
use crate::ast::types::Range;
|
||||||
use crate::cst::matchers::{match_expr, match_module};
|
use crate::cst::matchers::{match_expr, match_module};
|
||||||
use crate::fix::Fix;
|
use crate::fix::Fix;
|
||||||
use crate::python::string::strip_quotes_and_prefixes;
|
|
||||||
use crate::source_code::{Locator, Stylist};
|
use crate::source_code::{Locator, Stylist};
|
||||||
|
use ruff_python::string::strip_quotes_and_prefixes;
|
||||||
|
|
||||||
/// Generate a [`Fix`] to remove unused keys from format dict.
|
/// Generate a [`Fix`] to remove unused keys from format dict.
|
||||||
pub fn remove_unused_format_arguments_from_dict(
|
pub fn remove_unused_format_arguments_from_dict(
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::ast::types::Range;
|
use crate::ast::types::Range;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::python::future::ALL_FEATURE_NAMES;
|
|
||||||
use crate::registry::Diagnostic;
|
use crate::registry::Diagnostic;
|
||||||
use crate::violation::{Availability, Violation};
|
use crate::violation::{Availability, Violation};
|
||||||
use crate::{define_violation, AutofixKind};
|
use crate::{define_violation, AutofixKind};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruff_macros::derive_message_formats;
|
use ruff_macros::derive_message_formats;
|
||||||
|
use ruff_python::future::ALL_FEATURE_NAMES;
|
||||||
use rustpython_ast::Alias;
|
use rustpython_ast::Alias;
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ use crate::ast::helpers::{create_expr, create_stmt, unparse_stmt};
|
||||||
use crate::ast::types::Range;
|
use crate::ast::types::Range;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::Fix;
|
use crate::fix::Fix;
|
||||||
use crate::python::identifiers::is_identifier;
|
|
||||||
use crate::python::keyword::KWLIST;
|
|
||||||
use crate::registry::Diagnostic;
|
use crate::registry::Diagnostic;
|
||||||
use crate::source_code::Stylist;
|
use crate::source_code::Stylist;
|
||||||
|
use ruff_python::identifiers::is_identifier;
|
||||||
|
use ruff_python::keyword::KWLIST;
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
pub struct ConvertNamedTupleFunctionalToClass {
|
pub struct ConvertNamedTupleFunctionalToClass {
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ use crate::ast::helpers::{create_expr, create_stmt, unparse_stmt};
|
||||||
use crate::ast::types::Range;
|
use crate::ast::types::Range;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::Fix;
|
use crate::fix::Fix;
|
||||||
use crate::python::identifiers::is_identifier;
|
|
||||||
use crate::python::keyword::KWLIST;
|
|
||||||
use crate::registry::Diagnostic;
|
use crate::registry::Diagnostic;
|
||||||
use crate::source_code::Stylist;
|
use crate::source_code::Stylist;
|
||||||
|
use ruff_python::identifiers::is_identifier;
|
||||||
|
use ruff_python::keyword::KWLIST;
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
pub struct ConvertTypedDictFunctionalToClass {
|
pub struct ConvertTypedDictFunctionalToClass {
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,11 @@ use crate::ast::types::Range;
|
||||||
use crate::ast::whitespace::indentation;
|
use crate::ast::whitespace::indentation;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::Fix;
|
use crate::fix::Fix;
|
||||||
use crate::python::identifiers::is_identifier;
|
|
||||||
use crate::python::keyword::KWLIST;
|
|
||||||
use crate::registry::Diagnostic;
|
use crate::registry::Diagnostic;
|
||||||
use crate::rules::pydocstyle::helpers::{leading_quote, trailing_quote};
|
use crate::rules::pydocstyle::helpers::{leading_quote, trailing_quote};
|
||||||
use crate::rules::pyupgrade::helpers::curly_escape;
|
use crate::rules::pyupgrade::helpers::curly_escape;
|
||||||
|
use ruff_python::identifiers::is_identifier;
|
||||||
|
use ruff_python::keyword::KWLIST;
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
pub struct PrintfStringFormatting;
|
pub struct PrintfStringFormatting;
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,12 @@ use rustc_hash::FxHashSet;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{de, Deserialize, Deserializer, Serialize};
|
use serde::{de, Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
use super::hashable::HashableHashSet;
|
|
||||||
use crate::registry::Rule;
|
use crate::registry::Rule;
|
||||||
use crate::rule_selector::RuleSelector;
|
use crate::rule_selector::RuleSelector;
|
||||||
use crate::{fs, warn_user_once};
|
use crate::{fs, warn_user_once};
|
||||||
|
|
||||||
|
use super::hashable::HashableHashSet;
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize, Hash, JsonSchema,
|
Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize, Hash, JsonSchema,
|
||||||
)]
|
)]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "ruff_python"
|
||||||
|
version = "0.0.241"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
once_cell = { version = "1.16.0" }
|
||||||
|
regex = { version = "1.6.0" }
|
||||||
|
rustc-hash = { version = "1.1.0" }
|
||||||
|
|
@ -43,7 +43,7 @@ pub fn strip_quotes_and_prefixes(s: &str) -> &str {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::python::string::{is_lower, is_upper, strip_quotes_and_prefixes};
|
use crate::string::{is_lower, is_upper, strip_quotes_and_prefixes};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_lower() {
|
fn test_is_lower() {
|
||||||
|
|
@ -2,14 +2,12 @@
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use crate::settings::types::PythonVersion;
|
|
||||||
|
|
||||||
// See: https://pycqa.github.io/isort/docs/configuration/options.html#known-standard-library
|
// See: https://pycqa.github.io/isort/docs/configuration/options.html#known-standard-library
|
||||||
pub static KNOWN_STANDARD_LIBRARY: Lazy<FxHashMap<PythonVersion, FxHashSet<&'static str>>> =
|
pub static KNOWN_STANDARD_LIBRARY: Lazy<FxHashMap<(u32, u32), FxHashSet<&'static str>>> =
|
||||||
Lazy::new(|| {
|
Lazy::new(|| {
|
||||||
FxHashMap::from_iter([
|
FxHashMap::from_iter([
|
||||||
(
|
(
|
||||||
PythonVersion::Py37,
|
(3, 7),
|
||||||
FxHashSet::from_iter([
|
FxHashSet::from_iter([
|
||||||
"_ast",
|
"_ast",
|
||||||
"_dummy_thread",
|
"_dummy_thread",
|
||||||
|
|
@ -230,7 +228,7 @@ pub static KNOWN_STANDARD_LIBRARY: Lazy<FxHashMap<PythonVersion, FxHashSet<&'sta
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
PythonVersion::Py38,
|
(3, 8),
|
||||||
FxHashSet::from_iter([
|
FxHashSet::from_iter([
|
||||||
"_ast",
|
"_ast",
|
||||||
"_dummy_thread",
|
"_dummy_thread",
|
||||||
|
|
@ -450,7 +448,7 @@ pub static KNOWN_STANDARD_LIBRARY: Lazy<FxHashMap<PythonVersion, FxHashSet<&'sta
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
PythonVersion::Py39,
|
(3, 9),
|
||||||
FxHashSet::from_iter([
|
FxHashSet::from_iter([
|
||||||
"_ast",
|
"_ast",
|
||||||
"_thread",
|
"_thread",
|
||||||
|
|
@ -670,7 +668,7 @@ pub static KNOWN_STANDARD_LIBRARY: Lazy<FxHashMap<PythonVersion, FxHashSet<&'sta
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
PythonVersion::Py310,
|
(3, 10),
|
||||||
FxHashSet::from_iter([
|
FxHashSet::from_iter([
|
||||||
"_ast",
|
"_ast",
|
||||||
"_thread",
|
"_thread",
|
||||||
|
|
@ -888,7 +886,7 @@ pub static KNOWN_STANDARD_LIBRARY: Lazy<FxHashMap<PythonVersion, FxHashSet<&'sta
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
PythonVersion::Py311,
|
(3, 11),
|
||||||
FxHashSet::from_iter([
|
FxHashSet::from_iter([
|
||||||
"_ast",
|
"_ast",
|
||||||
"_thread",
|
"_thread",
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use rustpython_ast::{Expr, ExprKind};
|
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
|
||||||
|
|
||||||
// See: https://pypi.org/project/typing-extensions/
|
// See: https://pypi.org/project/typing-extensions/
|
||||||
pub static TYPING_EXTENSIONS: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
pub static TYPING_EXTENSIONS: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||||
|
|
@ -62,7 +59,7 @@ pub static TYPING_EXTENSIONS: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||||
});
|
});
|
||||||
|
|
||||||
// See: https://docs.python.org/3/library/typing.html
|
// See: https://docs.python.org/3/library/typing.html
|
||||||
const SUBSCRIPTS: &[&[&str]] = &[
|
pub const SUBSCRIPTS: &[&[&str]] = &[
|
||||||
// builtins
|
// builtins
|
||||||
&["", "dict"],
|
&["", "dict"],
|
||||||
&["", "frozenset"],
|
&["", "frozenset"],
|
||||||
|
|
@ -183,56 +180,15 @@ const SUBSCRIPTS: &[&[&str]] = &[
|
||||||
];
|
];
|
||||||
|
|
||||||
// See: https://docs.python.org/3/library/typing.html
|
// See: https://docs.python.org/3/library/typing.html
|
||||||
const PEP_593_SUBSCRIPTS: &[&[&str]] = &[
|
pub const PEP_593_SUBSCRIPTS: &[&[&str]] = &[
|
||||||
// `typing`
|
// `typing`
|
||||||
&["typing", "Annotated"],
|
&["typing", "Annotated"],
|
||||||
// `typing_extensions`
|
// `typing_extensions`
|
||||||
&["typing_extensions", "Annotated"],
|
&["typing_extensions", "Annotated"],
|
||||||
];
|
];
|
||||||
|
|
||||||
pub enum SubscriptKind {
|
|
||||||
AnnotatedSubscript,
|
|
||||||
PEP593AnnotatedSubscript,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn match_annotated_subscript(checker: &Checker, expr: &Expr) -> Option<SubscriptKind> {
|
|
||||||
if !matches!(
|
|
||||||
expr.node,
|
|
||||||
ExprKind::Name { .. } | ExprKind::Attribute { .. }
|
|
||||||
) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
checker.resolve_call_path(expr).and_then(|call_path| {
|
|
||||||
if SUBSCRIPTS.contains(&call_path.as_slice()) {
|
|
||||||
return Some(SubscriptKind::AnnotatedSubscript);
|
|
||||||
}
|
|
||||||
if PEP_593_SUBSCRIPTS.contains(&call_path.as_slice()) {
|
|
||||||
return Some(SubscriptKind::PEP593AnnotatedSubscript);
|
|
||||||
}
|
|
||||||
|
|
||||||
for module in &checker.settings.typing_modules {
|
|
||||||
let module_call_path = module.split('.').collect::<Vec<_>>();
|
|
||||||
if call_path.starts_with(&module_call_path) {
|
|
||||||
for subscript in SUBSCRIPTS.iter() {
|
|
||||||
if call_path.last() == subscript.last() {
|
|
||||||
return Some(SubscriptKind::AnnotatedSubscript);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for subscript in PEP_593_SUBSCRIPTS.iter() {
|
|
||||||
if call_path.last() == subscript.last() {
|
|
||||||
return Some(SubscriptKind::PEP593AnnotatedSubscript);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// See: https://peps.python.org/pep-0585/
|
// See: https://peps.python.org/pep-0585/
|
||||||
const PEP_585_BUILTINS_ELIGIBLE: &[&[&str]] = &[
|
pub const PEP_585_BUILTINS_ELIGIBLE: &[&[&str]] = &[
|
||||||
&["typing", "Dict"],
|
&["typing", "Dict"],
|
||||||
&["typing", "FrozenSet"],
|
&["typing", "FrozenSet"],
|
||||||
&["typing", "List"],
|
&["typing", "List"],
|
||||||
|
|
@ -241,21 +197,3 @@ const PEP_585_BUILTINS_ELIGIBLE: &[&[&str]] = &[
|
||||||
&["typing", "Type"],
|
&["typing", "Type"],
|
||||||
&["typing_extensions", "Type"],
|
&["typing_extensions", "Type"],
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Returns `true` if `Expr` represents a reference to a typing object with a
|
|
||||||
/// PEP 585 built-in.
|
|
||||||
pub fn is_pep585_builtin(checker: &Checker, expr: &Expr) -> bool {
|
|
||||||
checker.resolve_call_path(expr).map_or(false, |call_path| {
|
|
||||||
PEP_585_BUILTINS_ELIGIBLE.contains(&call_path.as_slice())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Callable {
|
|
||||||
ForwardRef,
|
|
||||||
Cast,
|
|
||||||
NewType,
|
|
||||||
TypeVar,
|
|
||||||
NamedTuple,
|
|
||||||
TypedDict,
|
|
||||||
MypyExtension,
|
|
||||||
}
|
|
||||||
|
|
@ -8,13 +8,13 @@ from pathlib import Path
|
||||||
from sphinx.ext.intersphinx import fetch_inventory
|
from sphinx.ext.intersphinx import fetch_inventory
|
||||||
|
|
||||||
URL = "https://docs.python.org/{}/objects.inv"
|
URL = "https://docs.python.org/{}/objects.inv"
|
||||||
PATH = Path("src") / "python" / "sys.rs"
|
PATH = Path("crates") / "ruff_python" / "src" / "sys.rs"
|
||||||
VERSIONS = [
|
VERSIONS: list[tuple[int, int]] = [
|
||||||
("3", "7"),
|
(3, 7),
|
||||||
("3", "8"),
|
(3, 8),
|
||||||
("3", "9"),
|
(3, 9),
|
||||||
("3", "10"),
|
(3, 10),
|
||||||
("3", "11"),
|
(3, 11),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -36,16 +36,14 @@ with PATH.open("w") as f:
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use crate::settings::types::PythonVersion;
|
|
||||||
|
|
||||||
// See: https://pycqa.github.io/isort/docs/configuration/options.html#known-standard-library
|
// See: https://pycqa.github.io/isort/docs/configuration/options.html#known-standard-library
|
||||||
pub static KNOWN_STANDARD_LIBRARY: Lazy<FxHashMap<PythonVersion, FxHashSet<&'static str>>> =
|
pub static KNOWN_STANDARD_LIBRARY: Lazy<FxHashMap<(u32, u32), FxHashSet<&'static str>>> =
|
||||||
Lazy::new(|| {
|
Lazy::new(|| {
|
||||||
FxHashMap::from_iter([
|
FxHashMap::from_iter([
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
for version_info in VERSIONS:
|
for (major, minor) in VERSIONS:
|
||||||
version = ".".join(version_info)
|
version = f"{major}.{minor}"
|
||||||
url = URL.format(version)
|
url = URL.format(version)
|
||||||
invdata = fetch_inventory(FakeApp(), "", url)
|
invdata = fetch_inventory(FakeApp(), "", url)
|
||||||
|
|
||||||
|
|
@ -67,7 +65,7 @@ pub static KNOWN_STANDARD_LIBRARY: Lazy<FxHashMap<PythonVersion, FxHashSet<&'sta
|
||||||
f.write(
|
f.write(
|
||||||
f"""\
|
f"""\
|
||||||
(
|
(
|
||||||
PythonVersion::Py{"".join(version_info)},
|
({major}, {minor}),
|
||||||
FxHashSet::from_iter([
|
FxHashSet::from_iter([
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue