Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f58345dee3 | ||
|
|
71c0da27bb | ||
|
|
8a2d1a3029 | ||
|
|
6161e56ea4 | ||
|
|
189c9d4683 |
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -780,7 +780,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.258"
|
||||
version = "0.0.259"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.8",
|
||||
@@ -1982,7 +1982,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.258"
|
||||
version = "0.0.259"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bisection",
|
||||
@@ -2063,7 +2063,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.258"
|
||||
version = "0.0.259"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
|
||||
@@ -137,7 +137,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.258'
|
||||
rev: 'v0.0.259'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.258"
|
||||
version = "0.0.259"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.258"
|
||||
version = "0.0.259"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
@@ -17,8 +17,9 @@ use ruff_python_ast::context::Context;
|
||||
use ruff_python_ast::helpers::{binding_range, extract_handled_exceptions, to_module_path};
|
||||
use ruff_python_ast::operations::{extract_all_names, AllNamesFlags};
|
||||
use ruff_python_ast::scope::{
|
||||
Binding, BindingId, BindingKind, ClassDef, Exceptions, ExecutionContext, FunctionDef, Lambda,
|
||||
Scope, ScopeId, ScopeKind, ScopeStack,
|
||||
Binding, BindingId, BindingKind, ClassDef, Exceptions, ExecutionContext, Export,
|
||||
FromImportation, FunctionDef, Importation, Lambda, Scope, ScopeId, ScopeKind, ScopeStack,
|
||||
StarImportation, SubmoduleImportation,
|
||||
};
|
||||
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
|
||||
use ruff_python_ast::types::{Node, Range, RefEquality};
|
||||
@@ -870,7 +871,10 @@ where
|
||||
self.add_binding(
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::SubmoduleImportation(name, full_name),
|
||||
kind: BindingKind::SubmoduleImportation(SubmoduleImportation {
|
||||
name,
|
||||
full_name,
|
||||
}),
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
@@ -889,15 +893,12 @@ where
|
||||
.as_ref()
|
||||
.map_or(false, |asname| asname == &alias.node.name);
|
||||
|
||||
// Given `import foo`, `name` and `full_name` would both be `foo`.
|
||||
// Given `import foo as bar`, `name` would be `bar` and `full_name` would
|
||||
// be `foo`.
|
||||
let name = alias.node.asname.as_ref().unwrap_or(&alias.node.name);
|
||||
let full_name = &alias.node.name;
|
||||
self.add_binding(
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::Importation(name, full_name),
|
||||
kind: BindingKind::Importation(Importation { name, full_name }),
|
||||
runtime_usage: None,
|
||||
synthetic_usage: if is_explicit_reexport {
|
||||
Some((self.ctx.scope_id(), Range::from(alias)))
|
||||
@@ -1191,7 +1192,10 @@ where
|
||||
self.add_binding(
|
||||
"*",
|
||||
Binding {
|
||||
kind: BindingKind::StarImportation(*level, module.clone()),
|
||||
kind: BindingKind::StarImportation(StarImportation {
|
||||
level: *level,
|
||||
module: module.clone(),
|
||||
}),
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
@@ -1264,7 +1268,10 @@ where
|
||||
self.add_binding(
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::FromImportation(name, full_name),
|
||||
kind: BindingKind::FromImportation(FromImportation {
|
||||
name,
|
||||
full_name,
|
||||
}),
|
||||
runtime_usage: None,
|
||||
synthetic_usage: if is_explicit_reexport {
|
||||
Some((self.ctx.scope_id(), Range::from(alias)))
|
||||
@@ -4163,8 +4170,9 @@ impl<'a> Checker<'a> {
|
||||
// import pyarrow.csv
|
||||
// print(pa.csv.read_csv("test.csv"))
|
||||
match &self.ctx.bindings[*index].kind {
|
||||
BindingKind::Importation(name, full_name)
|
||||
| BindingKind::SubmoduleImportation(name, full_name) => {
|
||||
BindingKind::Importation(Importation { name, full_name })
|
||||
| BindingKind::SubmoduleImportation(SubmoduleImportation { name, full_name }) =>
|
||||
{
|
||||
let has_alias = full_name
|
||||
.split('.')
|
||||
.last()
|
||||
@@ -4181,7 +4189,7 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
BindingKind::FromImportation(name, full_name) => {
|
||||
BindingKind::FromImportation(FromImportation { name, full_name }) => {
|
||||
let has_alias = full_name
|
||||
.split('.')
|
||||
.last()
|
||||
@@ -4219,7 +4227,9 @@ impl<'a> Checker<'a> {
|
||||
for scope_index in self.ctx.scope_stack.iter() {
|
||||
let scope = &self.ctx.scopes[*scope_index];
|
||||
for binding in scope.binding_ids().map(|index| &self.ctx.bindings[*index]) {
|
||||
if let BindingKind::StarImportation(level, module) = &binding.kind {
|
||||
if let BindingKind::StarImportation(StarImportation { level, module }) =
|
||||
&binding.kind
|
||||
{
|
||||
from_list.push(helpers::format_import_from(
|
||||
level.as_ref(),
|
||||
module.as_deref(),
|
||||
@@ -4437,7 +4447,7 @@ impl<'a> Checker<'a> {
|
||||
self.add_binding(
|
||||
id,
|
||||
Binding {
|
||||
kind: BindingKind::Export(all_names),
|
||||
kind: BindingKind::Export(Export { names: all_names }),
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
@@ -4700,7 +4710,7 @@ impl<'a> Checker<'a> {
|
||||
.get("__all__")
|
||||
.map(|index| &self.ctx.bindings[*index])
|
||||
.and_then(|binding| match &binding.kind {
|
||||
BindingKind::Export(names) => Some((names, binding.range)),
|
||||
BindingKind::Export(Export { names }) => Some((names, binding.range)),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
@@ -4732,7 +4742,7 @@ impl<'a> Checker<'a> {
|
||||
.get("__all__")
|
||||
.map(|index| &self.ctx.bindings[*index])
|
||||
.and_then(|binding| match &binding.kind {
|
||||
BindingKind::Export(names) => {
|
||||
BindingKind::Export(Export { names }) => {
|
||||
Some((names.iter().map(String::as_str).collect(), binding.range))
|
||||
}
|
||||
_ => None,
|
||||
@@ -4854,7 +4864,9 @@ impl<'a> Checker<'a> {
|
||||
if let Some((names, range)) = &all_names {
|
||||
let mut from_list = vec![];
|
||||
for binding in scope.binding_ids().map(|index| &self.ctx.bindings[*index]) {
|
||||
if let BindingKind::StarImportation(level, module) = &binding.kind {
|
||||
if let BindingKind::StarImportation(StarImportation { level, module }) =
|
||||
&binding.kind
|
||||
{
|
||||
from_list.push(helpers::format_import_from(
|
||||
level.as_ref(),
|
||||
module.as_deref(),
|
||||
@@ -4933,9 +4945,14 @@ impl<'a> Checker<'a> {
|
||||
let binding = &self.ctx.bindings[*index];
|
||||
|
||||
let full_name = match &binding.kind {
|
||||
BindingKind::Importation(.., full_name) => full_name,
|
||||
BindingKind::FromImportation(.., full_name) => full_name.as_str(),
|
||||
BindingKind::SubmoduleImportation(.., full_name) => full_name,
|
||||
BindingKind::Importation(Importation { full_name, .. }) => full_name,
|
||||
BindingKind::FromImportation(FromImportation { full_name, .. }) => {
|
||||
full_name.as_str()
|
||||
}
|
||||
BindingKind::SubmoduleImportation(SubmoduleImportation {
|
||||
full_name,
|
||||
..
|
||||
}) => full_name,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::checkers::tokens::check_tokens;
|
||||
use crate::directives::Directives;
|
||||
use crate::doc_lines::{doc_lines_from_ast, doc_lines_from_tokens};
|
||||
use crate::message::{Message, Source};
|
||||
use crate::noqa::{add_noqa, rule_is_ignored};
|
||||
use crate::noqa::add_noqa;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::rules::pycodestyle;
|
||||
use crate::settings::{flags, Settings};
|
||||
@@ -159,20 +159,13 @@ pub fn check_path(
|
||||
}
|
||||
}
|
||||
Err(parse_error) => {
|
||||
if settings.rules.enabled(Rule::SyntaxError) {
|
||||
pycodestyle::rules::syntax_error(&mut diagnostics, &parse_error);
|
||||
}
|
||||
|
||||
// If the syntax error is ignored, suppress it (regardless of whether
|
||||
// `Rule::SyntaxError` is enabled).
|
||||
if !rule_is_ignored(
|
||||
Rule::SyntaxError,
|
||||
parse_error.location.row(),
|
||||
&directives.noqa_line_for,
|
||||
locator,
|
||||
) {
|
||||
error = Some(parse_error);
|
||||
}
|
||||
// Always add a diagnostic for the syntax error, regardless of whether
|
||||
// `Rule::SyntaxError` is enabled. We avoid propagating the syntax error
|
||||
// if it's disabled via any of the usual mechanisms (e.g., `noqa`,
|
||||
// `per-file-ignores`), and the easiest way to detect that suppression is
|
||||
// to see if the diagnostic persists to the end of the function.
|
||||
pycodestyle::rules::syntax_error(&mut diagnostics, &parse_error);
|
||||
error = Some(parse_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,6 +223,23 @@ pub fn check_path(
|
||||
}
|
||||
}
|
||||
|
||||
// If there was a syntax error, check if it should be discarded.
|
||||
if error.is_some() {
|
||||
// If the syntax error was removed by _any_ of the above disablement methods (e.g., a
|
||||
// `noqa` directive, or a `per-file-ignore`), discard it.
|
||||
if !diagnostics
|
||||
.iter()
|
||||
.any(|diagnostic| diagnostic.kind.rule() == Rule::SyntaxError)
|
||||
{
|
||||
error = None;
|
||||
}
|
||||
|
||||
// If the syntax error _diagnostic_ is disabled, discard the _diagnostic_.
|
||||
if !settings.rules.enabled(Rule::SyntaxError) {
|
||||
diagnostics.retain(|diagnostic| diagnostic.kind.rule() != Rule::SyntaxError);
|
||||
}
|
||||
}
|
||||
|
||||
LinterResult::new(diagnostics, error)
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ impl RuleSet {
|
||||
let mut i = 0;
|
||||
|
||||
while i < self.0.len() {
|
||||
self.0[i] ^= other.0[i];
|
||||
self.0[i] &= !other.0[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
@@ -362,4 +362,15 @@ mod tests {
|
||||
let expected_rules: Vec<_> = Rule::iter().collect();
|
||||
assert_eq!(all_rules, expected_rules);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_not_existing_rule_from_set() {
|
||||
let mut set = RuleSet::default();
|
||||
|
||||
set.remove(Rule::AmbiguousFunctionName);
|
||||
|
||||
assert!(!set.contains(Rule::AmbiguousFunctionName));
|
||||
assert!(set.is_empty());
|
||||
assert_eq!(set.into_iter().collect::<Vec<_>>(), vec![]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::scope::{Binding, BindingKind, ExecutionContext};
|
||||
use ruff_python_ast::scope::{
|
||||
Binding, BindingKind, ExecutionContext, FromImportation, Importation, SubmoduleImportation,
|
||||
};
|
||||
|
||||
#[violation]
|
||||
pub struct RuntimeImportInTypeCheckingBlock {
|
||||
@@ -21,9 +23,9 @@ impl Violation for RuntimeImportInTypeCheckingBlock {
|
||||
/// TCH004
|
||||
pub fn runtime_import_in_type_checking_block(binding: &Binding) -> Option<Diagnostic> {
|
||||
let full_name = match &binding.kind {
|
||||
BindingKind::Importation(.., full_name) => full_name,
|
||||
BindingKind::FromImportation(.., full_name) => full_name.as_str(),
|
||||
BindingKind::SubmoduleImportation(.., full_name) => full_name,
|
||||
BindingKind::Importation(Importation { full_name, .. }) => full_name,
|
||||
BindingKind::FromImportation(FromImportation { full_name, .. }) => full_name.as_str(),
|
||||
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => full_name,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ use std::path::Path;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::scope::{Binding, BindingKind, ExecutionContext};
|
||||
use ruff_python_ast::scope::{
|
||||
Binding, BindingKind, ExecutionContext, FromImportation, Importation, SubmoduleImportation,
|
||||
};
|
||||
|
||||
use crate::rules::isort::{categorize, ImportType};
|
||||
use crate::settings::Settings;
|
||||
@@ -55,30 +57,54 @@ impl Violation for TypingOnlyStandardLibraryImport {
|
||||
/// Return `true` if `this` is implicitly loaded via importing `that`.
|
||||
fn is_implicit_import(this: &Binding, that: &Binding) -> bool {
|
||||
match &this.kind {
|
||||
BindingKind::Importation(.., this_name)
|
||||
| BindingKind::SubmoduleImportation(this_name, ..) => match &that.kind {
|
||||
BindingKind::FromImportation(.., that_name) => {
|
||||
BindingKind::Importation(Importation {
|
||||
full_name: this_name,
|
||||
..
|
||||
})
|
||||
| BindingKind::SubmoduleImportation(SubmoduleImportation {
|
||||
name: this_name, ..
|
||||
}) => match &that.kind {
|
||||
BindingKind::FromImportation(FromImportation {
|
||||
full_name: that_name,
|
||||
..
|
||||
}) => {
|
||||
// Ex) `pkg.A` vs. `pkg`
|
||||
this_name
|
||||
.rfind('.')
|
||||
.map_or(false, |i| this_name[..i] == *that_name)
|
||||
}
|
||||
BindingKind::Importation(.., that_name)
|
||||
| BindingKind::SubmoduleImportation(that_name, ..) => {
|
||||
BindingKind::Importation(Importation {
|
||||
full_name: that_name,
|
||||
..
|
||||
})
|
||||
| BindingKind::SubmoduleImportation(SubmoduleImportation {
|
||||
name: that_name, ..
|
||||
}) => {
|
||||
// Ex) `pkg.A` vs. `pkg.B`
|
||||
this_name == that_name
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
BindingKind::FromImportation(.., this_name) => match &that.kind {
|
||||
BindingKind::Importation(.., that_name)
|
||||
| BindingKind::SubmoduleImportation(that_name, ..) => {
|
||||
BindingKind::FromImportation(FromImportation {
|
||||
full_name: this_name,
|
||||
..
|
||||
}) => match &that.kind {
|
||||
BindingKind::Importation(Importation {
|
||||
full_name: that_name,
|
||||
..
|
||||
})
|
||||
| BindingKind::SubmoduleImportation(SubmoduleImportation {
|
||||
name: that_name, ..
|
||||
}) => {
|
||||
// Ex) `pkg.A` vs. `pkg`
|
||||
this_name
|
||||
.rfind('.')
|
||||
.map_or(false, |i| &this_name[..i] == *that_name)
|
||||
}
|
||||
BindingKind::FromImportation(.., that_name) => {
|
||||
BindingKind::FromImportation(FromImportation {
|
||||
full_name: that_name,
|
||||
..
|
||||
}) => {
|
||||
// Ex) `pkg.A` vs. `pkg.B`
|
||||
this_name.rfind('.').map_or(false, |i| {
|
||||
that_name
|
||||
@@ -126,9 +152,9 @@ pub fn typing_only_runtime_import(
|
||||
}
|
||||
|
||||
let full_name = match &binding.kind {
|
||||
BindingKind::Importation(.., full_name) => full_name,
|
||||
BindingKind::FromImportation(.., full_name) => full_name.as_str(),
|
||||
BindingKind::SubmoduleImportation(.., full_name) => full_name,
|
||||
BindingKind::Importation(Importation { full_name, .. }) => full_name,
|
||||
BindingKind::FromImportation(FromImportation { full_name, .. }) => full_name.as_str(),
|
||||
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => full_name,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use rustpython_parser::ast::{Expr, ExprKind};
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::scope::BindingKind;
|
||||
use ruff_python_ast::scope::{BindingKind, Importation};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
@@ -86,7 +86,10 @@ pub fn check_call(checker: &mut Checker, func: &Expr) {
|
||||
// irrelevant bindings (like non-Pandas imports).
|
||||
if let ExprKind::Name { id, .. } = &value.node {
|
||||
if checker.ctx.find_binding(id).map_or(true, |binding| {
|
||||
if let BindingKind::Importation(.., module) = &binding.kind {
|
||||
if let BindingKind::Importation(Importation {
|
||||
full_name: module, ..
|
||||
}) = &binding.kind
|
||||
{
|
||||
module != &"pandas"
|
||||
} else {
|
||||
matches!(
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
#![allow(dead_code, unused_imports, unused_variables)]
|
||||
|
||||
use itertools::Itertools;
|
||||
use rustpython_parser::ast::Location;
|
||||
use rustpython_parser::Tok;
|
||||
|
||||
use ruff_diagnostics::DiagnosticKind;
|
||||
use ruff_diagnostics::Fix;
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::pycodestyle::helpers::{is_keyword_token, is_singleton_token};
|
||||
|
||||
#[violation]
|
||||
pub struct MissingWhitespace {
|
||||
pub token: String,
|
||||
@@ -40,21 +36,26 @@ pub fn missing_whitespace(
|
||||
indent_level: usize,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
for (idx, char) in line.chars().enumerate() {
|
||||
if idx + 1 == line.len() {
|
||||
break;
|
||||
}
|
||||
let next_char = line.chars().nth(idx + 1).unwrap();
|
||||
|
||||
if ",;:".contains(char) && !char::is_whitespace(next_char) {
|
||||
let before = &line[..idx];
|
||||
if char == ':'
|
||||
&& before.matches('[').count() > before.matches(']').count()
|
||||
&& before.rfind('{') < before.rfind('[')
|
||||
{
|
||||
let mut num_lsqb = 0;
|
||||
let mut num_rsqb = 0;
|
||||
let mut prev_lsqb = None;
|
||||
let mut prev_lbrace = None;
|
||||
for (idx, (char, next_char)) in line.chars().tuple_windows().enumerate() {
|
||||
if char == '[' {
|
||||
num_lsqb += 1;
|
||||
prev_lsqb = Some(idx);
|
||||
} else if char == ']' {
|
||||
num_rsqb += 1;
|
||||
} else if char == '{' {
|
||||
prev_lbrace = Some(idx);
|
||||
}
|
||||
|
||||
if (char == ',' || char == ';' || char == ':') && !char::is_whitespace(next_char) {
|
||||
if char == ':' && num_lsqb > num_rsqb && prev_lsqb > prev_lbrace {
|
||||
continue; // Slice syntax, no space required
|
||||
}
|
||||
if char == ',' && ")]".contains(next_char) {
|
||||
if char == ',' && (next_char == ')' || next_char == ']') {
|
||||
continue; // Allow tuple with only one element: (3,)
|
||||
}
|
||||
if char == ':' && next_char == '=' {
|
||||
|
||||
@@ -2,7 +2,9 @@ use rustpython_parser::ast::{Expr, ExprKind};
|
||||
|
||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::scope::BindingKind;
|
||||
use ruff_python_ast::scope::{
|
||||
BindingKind, FromImportation, Importation, StarImportation, SubmoduleImportation,
|
||||
};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
@@ -31,8 +33,10 @@ impl Violation for SysExitAlias {
|
||||
fn is_module_star_imported(checker: &Checker, module: &str) -> bool {
|
||||
checker.ctx.scopes().any(|scope| {
|
||||
scope.binding_ids().any(|index| {
|
||||
if let BindingKind::StarImportation(_, name) = &checker.ctx.bindings[*index].kind {
|
||||
name.as_ref().map(|name| name == module).unwrap_or_default()
|
||||
if let BindingKind::StarImportation(StarImportation { module: name, .. }) =
|
||||
&checker.ctx.bindings[*index].kind
|
||||
{
|
||||
name.as_ref().map_or(false, |name| name == module)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -50,7 +54,7 @@ fn get_member_import_name_alias(checker: &Checker, module: &str, member: &str) -
|
||||
// e.g. module=sys object=exit
|
||||
// `import sys` -> `sys.exit`
|
||||
// `import sys as sys2` -> `sys2.exit`
|
||||
BindingKind::Importation(name, full_name) => {
|
||||
BindingKind::Importation(Importation { name, full_name }) => {
|
||||
if full_name == &module {
|
||||
Some(format!("{name}.{member}"))
|
||||
} else {
|
||||
@@ -60,7 +64,7 @@ fn get_member_import_name_alias(checker: &Checker, module: &str, member: &str) -
|
||||
// e.g. module=os.path object=join
|
||||
// `from os.path import join` -> `join`
|
||||
// `from os.path import join as join2` -> `join2`
|
||||
BindingKind::FromImportation(name, full_name) => {
|
||||
BindingKind::FromImportation(FromImportation { name, full_name }) => {
|
||||
let mut parts = full_name.split('.');
|
||||
if parts.next() == Some(module)
|
||||
&& parts.next() == Some(member)
|
||||
@@ -73,8 +77,8 @@ fn get_member_import_name_alias(checker: &Checker, module: &str, member: &str) -
|
||||
}
|
||||
// e.g. module=os.path object=join
|
||||
// `from os.path import *` -> `join`
|
||||
BindingKind::StarImportation(_, name) => {
|
||||
if name.as_ref().map(|name| name == module).unwrap_or_default() {
|
||||
BindingKind::StarImportation(StarImportation { module: name, .. }) => {
|
||||
if name.as_ref().map_or(false, |name| name == module) {
|
||||
Some(member.to_string())
|
||||
} else {
|
||||
None
|
||||
@@ -82,7 +86,7 @@ fn get_member_import_name_alias(checker: &Checker, module: &str, member: &str) -
|
||||
}
|
||||
// e.g. module=os.path object=join
|
||||
// `import os.path ` -> `os.path.join`
|
||||
BindingKind::SubmoduleImportation(_, full_name) => {
|
||||
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => {
|
||||
if full_name == &module {
|
||||
Some(format!("{full_name}.{member}"))
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.258"
|
||||
version = "0.0.259"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
|
||||
@@ -10,8 +10,8 @@ use ruff_python_stdlib::typing::TYPING_EXTENSIONS;
|
||||
|
||||
use crate::helpers::{collect_call_path, from_relative_import};
|
||||
use crate::scope::{
|
||||
Binding, BindingId, BindingKind, Bindings, Exceptions, ExecutionContext, Scope, ScopeId,
|
||||
ScopeKind, ScopeStack, Scopes,
|
||||
Binding, BindingId, BindingKind, Bindings, Exceptions, ExecutionContext, FromImportation,
|
||||
Importation, Scope, ScopeId, ScopeKind, ScopeStack, Scopes, SubmoduleImportation,
|
||||
};
|
||||
use crate::types::{CallPath, RefEquality};
|
||||
use crate::typing::AnnotationKind;
|
||||
@@ -156,7 +156,10 @@ impl<'a> Context<'a> {
|
||||
return None;
|
||||
};
|
||||
match &binding.kind {
|
||||
BindingKind::Importation(.., name) | BindingKind::SubmoduleImportation(name, ..) => {
|
||||
BindingKind::Importation(Importation {
|
||||
full_name: name, ..
|
||||
})
|
||||
| BindingKind::SubmoduleImportation(SubmoduleImportation { name, .. }) => {
|
||||
if name.starts_with('.') {
|
||||
if let Some(module) = &self.module_path {
|
||||
let mut source_path = from_relative_import(module, name);
|
||||
@@ -171,7 +174,9 @@ impl<'a> Context<'a> {
|
||||
Some(source_path)
|
||||
}
|
||||
}
|
||||
BindingKind::FromImportation(.., name) => {
|
||||
BindingKind::FromImportation(FromImportation {
|
||||
full_name: name, ..
|
||||
}) => {
|
||||
if name.starts_with('.') {
|
||||
if let Some(module) = &self.module_path {
|
||||
let mut source_path = from_relative_import(module, name);
|
||||
|
||||
@@ -5,7 +5,7 @@ use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::helpers::any_over_expr;
|
||||
use crate::scope::{BindingKind, Scope};
|
||||
use crate::scope::{BindingKind, Export, Scope};
|
||||
use crate::visitor;
|
||||
use crate::visitor::Visitor;
|
||||
|
||||
@@ -96,7 +96,7 @@ pub fn extract_all_names(
|
||||
// Grab the existing bound __all__ values.
|
||||
if let StmtKind::AugAssign { .. } = &stmt.node {
|
||||
if let Some(index) = scope.get("__all__") {
|
||||
if let BindingKind::Export(existing) = &ctx.bindings[*index].kind {
|
||||
if let BindingKind::Export(Export { names: existing }) = &ctx.bindings[*index].kind {
|
||||
names.extend_from_slice(existing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,26 +284,45 @@ impl<'a> Binding<'a> {
|
||||
|
||||
pub fn redefines(&self, existing: &'a Binding) -> bool {
|
||||
match &self.kind {
|
||||
BindingKind::Importation(.., full_name) => {
|
||||
if let BindingKind::SubmoduleImportation(.., existing) = &existing.kind {
|
||||
BindingKind::Importation(Importation { full_name, .. }) => {
|
||||
if let BindingKind::SubmoduleImportation(SubmoduleImportation {
|
||||
full_name: existing,
|
||||
..
|
||||
}) = &existing.kind
|
||||
{
|
||||
return full_name == existing;
|
||||
}
|
||||
}
|
||||
BindingKind::FromImportation(.., full_name) => {
|
||||
if let BindingKind::SubmoduleImportation(.., existing) = &existing.kind {
|
||||
BindingKind::FromImportation(FromImportation { full_name, .. }) => {
|
||||
if let BindingKind::SubmoduleImportation(SubmoduleImportation {
|
||||
full_name: existing,
|
||||
..
|
||||
}) = &existing.kind
|
||||
{
|
||||
return full_name == existing;
|
||||
}
|
||||
}
|
||||
BindingKind::SubmoduleImportation(.., full_name) => match &existing.kind {
|
||||
BindingKind::Importation(.., existing)
|
||||
| BindingKind::SubmoduleImportation(.., existing) => {
|
||||
return full_name == existing;
|
||||
BindingKind::SubmoduleImportation(SubmoduleImportation { full_name, .. }) => {
|
||||
match &existing.kind {
|
||||
BindingKind::Importation(Importation {
|
||||
full_name: existing,
|
||||
..
|
||||
})
|
||||
| BindingKind::SubmoduleImportation(SubmoduleImportation {
|
||||
full_name: existing,
|
||||
..
|
||||
}) => {
|
||||
return full_name == existing;
|
||||
}
|
||||
BindingKind::FromImportation(FromImportation {
|
||||
full_name: existing,
|
||||
..
|
||||
}) => {
|
||||
return full_name == existing;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
BindingKind::FromImportation(.., existing) => {
|
||||
return full_name == existing;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
BindingKind::Annotation => {
|
||||
return false;
|
||||
}
|
||||
@@ -366,6 +385,54 @@ impl nohash_hasher::IsEnabled for BindingId {}
|
||||
// StarImportation
|
||||
// FutureImportation
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Export {
|
||||
/// The names of the bindings exported via `__all__`.
|
||||
pub names: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StarImportation {
|
||||
/// The level of the import. `None` or `Some(0)` indicate an absolute import.
|
||||
pub level: Option<usize>,
|
||||
/// The module being imported. `None` indicates a wildcard import.
|
||||
pub module: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Importation<'a> {
|
||||
/// The name to which the import is bound.
|
||||
/// Given `import foo`, `name` would be "foo".
|
||||
/// Given `import foo as bar`, `name` would be "bar".
|
||||
pub name: &'a str,
|
||||
/// The full name of the module being imported.
|
||||
/// Given `import foo`, `full_name` would be "foo".
|
||||
/// Given `import foo as bar`, `full_name` would be "foo".
|
||||
pub full_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FromImportation<'a> {
|
||||
/// The name to which the import is bound.
|
||||
/// Given `from foo import bar`, `name` would be "bar".
|
||||
/// Given `from foo import bar as baz`, `name` would be "baz".
|
||||
pub name: &'a str,
|
||||
/// The full name of the module being imported.
|
||||
/// Given `from foo import bar`, `full_name` would be "foo.bar".
|
||||
/// Given `from foo import bar as baz`, `full_name` would be "foo.bar".
|
||||
pub full_name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SubmoduleImportation<'a> {
|
||||
/// The parent module imported by the submodule import.
|
||||
/// Given `import foo.bar`, `module` would be "foo".
|
||||
pub name: &'a str,
|
||||
/// The full name of the submodule being imported.
|
||||
/// Given `import foo.bar`, `full_name` would be "foo.bar".
|
||||
pub full_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, is_macro::Is)]
|
||||
pub enum BindingKind<'a> {
|
||||
Annotation,
|
||||
@@ -378,12 +445,12 @@ pub enum BindingKind<'a> {
|
||||
Builtin,
|
||||
ClassDefinition,
|
||||
FunctionDefinition,
|
||||
Export(Vec<String>),
|
||||
Export(Export),
|
||||
FutureImportation,
|
||||
StarImportation(Option<usize>, Option<String>),
|
||||
Importation(&'a str, &'a str),
|
||||
FromImportation(&'a str, String),
|
||||
SubmoduleImportation(&'a str, &'a str),
|
||||
StarImportation(StarImportation),
|
||||
Importation(Importation<'a>),
|
||||
FromImportation(FromImportation<'a>),
|
||||
SubmoduleImportation(SubmoduleImportation<'a>),
|
||||
}
|
||||
|
||||
/// The bindings in a program.
|
||||
|
||||
@@ -242,7 +242,7 @@ This tutorial has focused on Ruff's command-line interface, but Ruff can also be
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.258'
|
||||
rev: 'v0.0.259'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
|
||||
@@ -20,7 +20,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.258'
|
||||
rev: 'v0.0.259'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -30,7 +30,7 @@ Or, to enable autofix:
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.258'
|
||||
rev: 'v0.0.259'
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "ruff"
|
||||
version = "0.0.258"
|
||||
version = "0.0.259"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
authors = [{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }]
|
||||
maintainers = [{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }]
|
||||
|
||||
Reference in New Issue
Block a user