Remove AST checker's dependency on resolver (#3368)

This commit is contained in:
Charlie Marsh 2023-03-06 16:45:09 -05:00 committed by GitHub
parent 074f5634a5
commit 8437399496
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 62 additions and 58 deletions

View file

@ -5,12 +5,12 @@ use rustc_hash::FxHashMap;
use rustpython_parser::ast::{Expr, Stmt}; use rustpython_parser::ast::{Expr, Stmt};
use smallvec::smallvec; use smallvec::smallvec;
use ruff_python_stdlib::path::is_python_stub_file;
use ruff_python_stdlib::typing::TYPING_EXTENSIONS; use ruff_python_stdlib::typing::TYPING_EXTENSIONS;
use crate::ast::helpers::{collect_call_path, from_relative_import, Exceptions}; use crate::ast::helpers::{collect_call_path, from_relative_import, Exceptions};
use crate::ast::types::{Binding, BindingKind, CallPath, ExecutionContext, RefEquality, Scope}; use crate::ast::types::{Binding, BindingKind, CallPath, ExecutionContext, RefEquality, Scope};
use crate::ast::visibility::{module_visibility, Modifier, VisibleScope}; use crate::ast::visibility::{module_visibility, Modifier, VisibleScope};
use crate::resolver::is_interface_definition_path;
#[allow(clippy::struct_excessive_bools)] #[allow(clippy::struct_excessive_bools)]
pub struct Context<'a> { pub struct Context<'a> {
@ -82,7 +82,7 @@ impl<'a> Context<'a> {
in_type_checking_block: false, in_type_checking_block: false,
seen_import_boundary: false, seen_import_boundary: false,
futures_allowed: true, futures_allowed: true,
annotations_future_enabled: is_interface_definition_path(path), annotations_future_enabled: is_python_stub_file(path),
handled_exceptions: Vec::default(), handled_exceptions: Vec::default(),
} }
} }

View file

@ -14,6 +14,7 @@ use rustpython_parser::ast::{
}; };
use ruff_python_stdlib::builtins::{BUILTINS, MAGIC_GLOBALS}; use ruff_python_stdlib::builtins::{BUILTINS, MAGIC_GLOBALS};
use ruff_python_stdlib::path::is_python_stub_file;
use crate::ast::context::Context; use crate::ast::context::Context;
use crate::ast::helpers::{binding_range, extract_handled_exceptions, to_module_path, Exceptions}; use crate::ast::helpers::{binding_range, extract_handled_exceptions, to_module_path, Exceptions};
@ -31,7 +32,6 @@ use crate::docstrings::definition::{
transition_scope, Definition, DefinitionKind, Docstring, Documentable, transition_scope, Definition, DefinitionKind, Docstring, Documentable,
}; };
use crate::registry::{Diagnostic, Rule}; use crate::registry::{Diagnostic, Rule};
use crate::resolver::is_interface_definition_path;
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,
flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez, flake8_debugger, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez, flake8_debugger,
@ -58,7 +58,7 @@ pub struct Checker<'a> {
pub path: &'a Path, pub path: &'a Path,
module_path: Option<Vec<String>>, module_path: Option<Vec<String>>,
package: Option<&'a Path>, package: Option<&'a Path>,
is_interface_definition: bool, is_stub: bool,
autofix: flags::Autofix, autofix: flags::Autofix,
noqa: flags::Noqa, noqa: flags::Noqa,
pub settings: &'a Settings, pub settings: &'a Settings,
@ -97,7 +97,7 @@ impl<'a> Checker<'a> {
path, path,
package, package,
module_path: module_path.clone(), module_path: module_path.clone(),
is_interface_definition: is_interface_definition_path(path), is_stub: is_python_stub_file(path),
locator, locator,
stylist: style, stylist: style,
indexer, indexer,
@ -378,7 +378,7 @@ where
} }
} }
if self.is_interface_definition { if self.is_stub {
if self.settings.rules.enabled(&Rule::PassStatementStubBody) { if self.settings.rules.enabled(&Rule::PassStatementStubBody) {
flake8_pyi::rules::pass_statement_stub_body(self, body); flake8_pyi::rules::pass_statement_stub_body(self, body);
} }
@ -756,7 +756,7 @@ where
flake8_bugbear::rules::useless_expression(self, body); flake8_bugbear::rules::useless_expression(self, body);
} }
if !self.is_interface_definition { if !self.is_stub {
if self if self
.settings .settings
.rules .rules
@ -771,7 +771,7 @@ where
); );
} }
} }
if self.is_interface_definition { if self.is_stub {
if self.settings.rules.enabled(&Rule::PassStatementStubBody) { if self.settings.rules.enabled(&Rule::PassStatementStubBody) {
flake8_pyi::rules::pass_statement_stub_body(self, body); flake8_pyi::rules::pass_statement_stub_body(self, body);
} }
@ -1805,7 +1805,7 @@ where
} }
} }
if self.is_interface_definition { if self.is_stub {
if self.settings.rules.enabled(&Rule::PrefixTypeParams) { if self.settings.rules.enabled(&Rule::PrefixTypeParams) {
flake8_pyi::rules::prefix_type_params(self, value, targets); flake8_pyi::rules::prefix_type_params(self, value, targets);
} }
@ -3301,7 +3301,7 @@ where
flake8_simplify::rules::yoda_conditions(self, expr, left, ops, comparators); flake8_simplify::rules::yoda_conditions(self, expr, left, ops, comparators);
} }
if self.is_interface_definition { if self.is_stub {
if self if self
.settings .settings
.rules .rules
@ -3886,7 +3886,7 @@ where
flake8_bugbear::rules::function_call_argument_default(self, arguments); flake8_bugbear::rules::function_call_argument_default(self, arguments);
} }
if self.is_interface_definition { if self.is_stub {
if self if self
.settings .settings
.rules .rules
@ -3895,7 +3895,7 @@ where
flake8_pyi::rules::typed_argument_simple_defaults(self, arguments); flake8_pyi::rules::typed_argument_simple_defaults(self, arguments);
} }
} }
if self.is_interface_definition { if self.is_stub {
if self.settings.rules.enabled(&Rule::ArgumentSimpleDefaults) { if self.settings.rules.enabled(&Rule::ArgumentSimpleDefaults) {
flake8_pyi::rules::argument_simple_defaults(self, arguments); flake8_pyi::rules::argument_simple_defaults(self, arguments);
} }
@ -4710,7 +4710,7 @@ impl<'a> Checker<'a> {
} }
fn check_dead_scopes(&mut self) { fn check_dead_scopes(&mut self) {
let enforce_typing_imports = !self.is_interface_definition let enforce_typing_imports = !self.is_stub
&& (self && (self
.settings .settings
.rules .rules
@ -5241,7 +5241,7 @@ impl<'a> Checker<'a> {
} }
overloaded_name = flake8_annotations::helpers::overloaded_name(self, &definition); overloaded_name = flake8_annotations::helpers::overloaded_name(self, &definition);
} }
if self.is_interface_definition { if self.is_stub {
if self.settings.rules.enabled(&Rule::DocstringInStub) { if self.settings.rules.enabled(&Rule::DocstringInStub) {
flake8_pyi::rules::docstring_in_stubs(self, definition.docstring); flake8_pyi::rules::docstring_in_stubs(self, definition.docstring);
} }

View file

@ -18,7 +18,7 @@ pub fn check_tokens(
tokens: &[LexResult], tokens: &[LexResult],
settings: &Settings, settings: &Settings,
autofix: flags::Autofix, autofix: flags::Autofix,
is_interface_definition: bool, is_stub: bool,
) -> Vec<Diagnostic> { ) -> Vec<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = vec![]; let mut diagnostics: Vec<Diagnostic> = vec![];
@ -164,7 +164,7 @@ pub fn check_tokens(
} }
// PYI033 // PYI033
if enforce_type_comment_in_stub && is_interface_definition { if enforce_type_comment_in_stub && is_stub {
diagnostics.extend(flake8_pyi::rules::type_comment_in_stub(tokens)); diagnostics.extend(flake8_pyi::rules::type_comment_in_stub(tokens));
} }

View file

@ -4,6 +4,7 @@ use std::path::Path;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use colored::Colorize; use colored::Colorize;
use log::error; use log::error;
use ruff_python_stdlib::path::is_python_stub_file;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use rustpython_parser::lexer::LexResult; use rustpython_parser::lexer::LexResult;
use rustpython_parser::ParseError; use rustpython_parser::ParseError;
@ -21,7 +22,6 @@ use crate::doc_lines::{doc_lines_from_ast, doc_lines_from_tokens};
use crate::message::{Message, Source}; use crate::message::{Message, Source};
use crate::noqa::{add_noqa, rule_is_ignored}; use crate::noqa::{add_noqa, rule_is_ignored};
use crate::registry::{Diagnostic, Rule}; use crate::registry::{Diagnostic, Rule};
use crate::resolver::is_interface_definition_path;
use crate::rules::pycodestyle; use crate::rules::pycodestyle;
use crate::settings::{flags, Settings}; use crate::settings::{flags, Settings};
use crate::source_code::{Indexer, Locator, Stylist}; use crate::source_code::{Indexer, Locator, Stylist};
@ -84,14 +84,8 @@ pub fn check_path(
.iter_enabled() .iter_enabled()
.any(|rule_code| rule_code.lint_source().is_tokens()) .any(|rule_code| rule_code.lint_source().is_tokens())
{ {
let is_interface_definition = is_interface_definition_path(path); let is_stub = is_python_stub_file(path);
diagnostics.extend(check_tokens( diagnostics.extend(check_tokens(locator, &tokens, settings, autofix, is_stub));
locator,
&tokens,
settings,
autofix,
is_interface_definition,
));
} }
// Run the filesystem-based rules. // Run the filesystem-based rules.

View file

@ -10,6 +10,7 @@ use ignore::{DirEntry, WalkBuilder, WalkState};
use itertools::Itertools; use itertools::Itertools;
use log::debug; use log::debug;
use path_absolutize::path_dedot; use path_absolutize::path_dedot;
use ruff_python_stdlib::path::is_python_file;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use crate::fs; use crate::fs;
@ -191,20 +192,9 @@ fn match_exclusion(file_path: &str, file_basename: &str, exclusion: &globset::Gl
exclusion.is_match(file_path) || exclusion.is_match(file_basename) exclusion.is_match(file_path) || exclusion.is_match(file_basename)
} }
/// Return `true` if the [`Path`] appears to be that of a Python file.
fn is_python_path(path: &Path) -> bool {
path.extension()
.map_or(false, |ext| ext == "py" || ext == "pyi")
}
/// Return `true` if the [`Path`] appears to be that of a Python interface definition file (`.pyi`).
pub fn is_interface_definition_path(path: &Path) -> bool {
path.extension().map_or(false, |ext| ext == "pyi")
}
/// Return `true` if the [`DirEntry`] appears to be that of a Python file. /// Return `true` if the [`DirEntry`] appears to be that of a Python file.
pub fn is_python_entry(entry: &DirEntry) -> bool { pub fn is_python_entry(entry: &DirEntry) -> bool {
is_python_path(entry.path()) is_python_file(entry.path())
&& !entry && !entry
.file_type() .file_type()
.map_or(false, |file_type| file_type.is_dir()) .map_or(false, |file_type| file_type.is_dir())
@ -430,28 +420,13 @@ mod tests {
use crate::fs; use crate::fs;
use crate::resolver::{ use crate::resolver::{
is_file_excluded, is_python_path, match_exclusion, resolve_settings_with_processor, is_file_excluded, match_exclusion, resolve_settings_with_processor, NoOpProcessor,
NoOpProcessor, PyprojectDiscovery, Relativity, Resolver, PyprojectDiscovery, Relativity, Resolver,
}; };
use crate::settings::pyproject::find_settings_toml; use crate::settings::pyproject::find_settings_toml;
use crate::settings::types::FilePattern; use crate::settings::types::FilePattern;
use crate::test::test_resource_path; use crate::test::test_resource_path;
#[test]
fn inclusions() {
let path = Path::new("foo/bar/baz.py").absolutize().unwrap();
assert!(is_python_path(&path));
let path = Path::new("foo/bar/baz.pyi").absolutize().unwrap();
assert!(is_python_path(&path));
let path = Path::new("foo/bar/baz.js").absolutize().unwrap();
assert!(!is_python_path(&path));
let path = Path::new("foo/bar/baz").absolutize().unwrap();
assert!(!is_python_path(&path));
}
fn make_exclusion(file_pattern: FilePattern) -> GlobSet { fn make_exclusion(file_pattern: FilePattern) -> GlobSet {
let mut builder = globset::GlobSetBuilder::new(); let mut builder = globset::GlobSetBuilder::new();
file_pattern.add_to(&mut builder).unwrap(); file_pattern.add_to(&mut builder).unwrap();

View file

@ -1,5 +1,6 @@
use std::path::Path; use std::path::Path;
use ruff_python_stdlib::path::is_python_stub_file;
use rustpython_parser::ast::{ use rustpython_parser::ast::{
Alias, Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, Excepthandler, Alias, Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, Excepthandler,
ExcepthandlerKind, Expr, ExprContext, Keyword, MatchCase, Operator, Pattern, Stmt, StmtKind, ExcepthandlerKind, Expr, ExprContext, Keyword, MatchCase, Operator, Pattern, Stmt, StmtKind,
@ -9,7 +10,6 @@ use rustpython_parser::ast::{
use super::helpers; use super::helpers;
use crate::ast::visitor::Visitor; use crate::ast::visitor::Visitor;
use crate::directives::IsortDirectives; use crate::directives::IsortDirectives;
use crate::resolver::is_interface_definition_path;
use crate::source_code::Locator; use crate::source_code::Locator;
#[derive(Debug)] #[derive(Debug)]
@ -29,7 +29,7 @@ pub struct Block<'a> {
pub struct ImportTracker<'a> { pub struct ImportTracker<'a> {
locator: &'a Locator<'a>, locator: &'a Locator<'a>,
directives: &'a IsortDirectives, directives: &'a IsortDirectives,
pyi: bool, is_stub: bool,
blocks: Vec<Block<'a>>, blocks: Vec<Block<'a>>,
split_index: usize, split_index: usize,
nested: bool, nested: bool,
@ -40,7 +40,7 @@ impl<'a> ImportTracker<'a> {
Self { Self {
locator, locator,
directives, directives,
pyi: is_interface_definition_path(path), is_stub: is_python_stub_file(path),
blocks: vec![Block::default()], blocks: vec![Block::default()],
split_index: 0, split_index: 0,
nested: false, nested: false,
@ -65,7 +65,7 @@ impl<'a> ImportTracker<'a> {
return None; return None;
} }
Some(if self.pyi { Some(if self.is_stub {
// Black treats interface files differently, limiting to one newline // Black treats interface files differently, limiting to one newline
// (`Trailing::Sibling`). // (`Trailing::Sibling`).
Trailer::Sibling Trailer::Sibling

View file

@ -3,6 +3,7 @@ pub mod bytes;
pub mod future; pub mod future;
pub mod identifiers; pub mod identifiers;
pub mod keyword; pub mod keyword;
pub mod path;
pub mod str; pub mod str;
pub mod sys; pub mod sys;
pub mod typing; pub mod typing;

View file

@ -0,0 +1,34 @@
use std::path::Path;
/// Return `true` if the [`Path`] appears to be that of a Python file.
pub fn is_python_file(path: &Path) -> bool {
path.extension()
.map_or(false, |ext| ext == "py" || ext == "pyi")
}
/// Return `true` if the [`Path`] appears to be that of a Python interface definition file (`.pyi`).
pub fn is_python_stub_file(path: &Path) -> bool {
path.extension().map_or(false, |ext| ext == "pyi")
}
#[cfg(test)]
mod tests {
use std::path::Path;
use crate::path::is_python_file;
#[test]
fn inclusions() {
let path = Path::new("foo/bar/baz.py");
assert!(is_python_file(path));
let path = Path::new("foo/bar/baz.pyi");
assert!(is_python_file(path));
let path = Path::new("foo/bar/baz.js");
assert!(!is_python_file(path));
let path = Path::new("foo/bar/baz");
assert!(!is_python_file(path));
}
}