Move RustPython vendored and helper code into its own crate (#3171)

This commit is contained in:
Charlie Marsh 2023-02-23 09:14:16 -05:00 committed by GitHub
parent 0f04aa2a5f
commit 095f005bf4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 58 additions and 57 deletions

12
Cargo.lock generated
View file

@ -1985,6 +1985,7 @@ dependencies = [
"result-like", "result-like",
"ruff_macros", "ruff_macros",
"ruff_python", "ruff_python",
"ruff_rustpython",
"rustc-hash", "rustc-hash",
"rustpython-common", "rustpython-common",
"rustpython-parser", "rustpython-parser",
@ -2109,6 +2110,7 @@ dependencies = [
"insta", "insta",
"once_cell", "once_cell",
"ruff_formatter", "ruff_formatter",
"ruff_rustpython",
"ruff_testing_macros", "ruff_testing_macros",
"ruff_text_size", "ruff_text_size",
"rustc-hash", "rustc-hash",
@ -2118,6 +2120,16 @@ dependencies = [
"test-case", "test-case",
] ]
[[package]]
name = "ruff_rustpython"
version = "0.0.0"
dependencies = [
"anyhow",
"once_cell",
"rustpython-common",
"rustpython-parser",
]
[[package]] [[package]]
name = "ruff_testing_macros" name = "ruff_testing_macros"
version = "0.0.0" version = "0.0.0"

View file

@ -16,6 +16,10 @@ crate-type = ["cdylib", "rlib"]
doctest = false doctest = false
[dependencies] [dependencies]
ruff_macros = { path = "../ruff_macros" }
ruff_python = { path = "../ruff_python" }
ruff_rustpython = { path = "../ruff_rustpython" }
anyhow = { workspace = true } anyhow = { workspace = true }
bisection = { version = "0.1.0" } bisection = { version = "0.1.0" }
bitflags = { version = "1.3.2" } bitflags = { version = "1.3.2" }
@ -40,8 +44,6 @@ once_cell = { workspace = true }
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 = { workspace = true } regex = { workspace = true }
result-like = "0.4.6" result-like = "0.4.6"
ruff_macros = { path = "../ruff_macros" }
ruff_python = { path = "../ruff_python" }
rustc-hash = { workspace = true } rustc-hash = { workspace = true }
rustpython-common = { workspace = true } rustpython-common = { workspace = true }
rustpython-parser = { workspace = true } rustpython-parser = { workspace = true }

View file

@ -33,10 +33,8 @@ pub mod resolver;
mod rule_redirects; mod rule_redirects;
mod rule_selector; mod rule_selector;
mod rules; mod rules;
mod rustpython_helpers;
pub mod settings; pub mod settings;
pub mod source_code; pub mod source_code;
mod vendor;
mod violation; mod violation;
mod visibility; mod visibility;

View file

@ -14,7 +14,6 @@ use crate::rules::{
flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments,
isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade, isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade,
}; };
use crate::rustpython_helpers::tokenize;
use crate::settings::configuration::Configuration; use crate::settings::configuration::Configuration;
use crate::settings::options::Options; use crate::settings::options::Options;
use crate::settings::{defaults, flags, Settings}; use crate::settings::{defaults, flags, Settings};
@ -175,7 +174,7 @@ pub fn check(contents: &str, options: JsValue) -> Result<JsValue, JsValue> {
Settings::from_configuration(configuration, Path::new(".")).map_err(|e| e.to_string())?; Settings::from_configuration(configuration, Path::new(".")).map_err(|e| e.to_string())?;
// Tokenize once. // Tokenize once.
let tokens: Vec<LexResult> = tokenize(contents); let tokens: Vec<LexResult> = ruff_rustpython::tokenize(contents);
// Map row and column locations to byte slices (lazily). // Map row and column locations to byte slices (lazily).
let locator = Locator::new(contents); let locator = Locator::new(contents);

View file

@ -24,7 +24,7 @@ use crate::registry::{Diagnostic, LintSource, Rule};
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};
use crate::{directives, fs, rustpython_helpers}; use crate::{directives, fs};
const CARGO_PKG_NAME: &str = env!("CARGO_PKG_NAME"); const CARGO_PKG_NAME: &str = env!("CARGO_PKG_NAME");
const CARGO_PKG_REPOSITORY: &str = env!("CARGO_PKG_REPOSITORY"); const CARGO_PKG_REPOSITORY: &str = env!("CARGO_PKG_REPOSITORY");
@ -115,7 +115,7 @@ pub fn check_path(
.iter_enabled() .iter_enabled()
.any(|rule_code| matches!(rule_code.lint_source(), LintSource::Imports)); .any(|rule_code| matches!(rule_code.lint_source(), LintSource::Imports));
if use_ast || use_imports || use_doc_lines { if use_ast || use_imports || use_doc_lines {
match rustpython_helpers::parse_program_tokens(tokens, &path.to_string_lossy()) { match ruff_rustpython::parse_program_tokens(tokens, &path.to_string_lossy()) {
Ok(python_ast) => { Ok(python_ast) => {
if use_ast { if use_ast {
diagnostics.extend(check_ast( diagnostics.extend(check_ast(
@ -226,7 +226,7 @@ pub fn add_noqa_to_path(path: &Path, package: Option<&Path>, settings: &Settings
let contents = std::fs::read_to_string(path)?; let contents = std::fs::read_to_string(path)?;
// Tokenize once. // Tokenize once.
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents); let tokens: Vec<LexResult> = ruff_rustpython::tokenize(&contents);
// Map row and column locations to byte slices (lazily). // Map row and column locations to byte slices (lazily).
let locator = Locator::new(&contents); let locator = Locator::new(&contents);
@ -290,7 +290,7 @@ pub fn lint_only(
autofix: flags::Autofix, autofix: flags::Autofix,
) -> LinterResult<Vec<Message>> { ) -> LinterResult<Vec<Message>> {
// Tokenize once. // Tokenize once.
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(contents); let tokens: Vec<LexResult> = ruff_rustpython::tokenize(contents);
// Map row and column locations to byte slices (lazily). // Map row and column locations to byte slices (lazily).
let locator = Locator::new(contents); let locator = Locator::new(contents);
@ -359,7 +359,7 @@ pub fn lint_fix<'a>(
// Continuously autofix until the source code stabilizes. // Continuously autofix until the source code stabilizes.
loop { loop {
// Tokenize once. // Tokenize once.
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&transformed); let tokens: Vec<LexResult> = ruff_rustpython::tokenize(&transformed);
// Map row and column locations to byte slices (lazily). // Map row and column locations to byte slices (lazily).
let locator = Locator::new(&transformed); let locator = Locator::new(&transformed);

View file

@ -18,12 +18,12 @@ mod tests {
use crate::settings::flags; use crate::settings::flags;
use crate::source_code::{Indexer, Locator, Stylist}; use crate::source_code::{Indexer, Locator, Stylist};
use crate::test::test_path; use crate::test::test_path;
use crate::{directives, rustpython_helpers, settings}; use crate::{directives, settings};
fn rule_code(contents: &str, expected: &[Rule]) { fn rule_code(contents: &str, expected: &[Rule]) {
let contents = dedent(contents); let contents = dedent(contents);
let settings = settings::Settings::for_rules(&Linter::PandasVet); let settings = settings::Settings::for_rules(&Linter::PandasVet);
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents); let tokens: Vec<LexResult> = ruff_rustpython::tokenize(&contents);
let locator = Locator::new(&contents); let locator = Locator::new(&contents);
let stylist = Stylist::from_contents(&contents, &locator); let stylist = Stylist::from_contents(&contents, &locator);
let indexer: Indexer = tokens.as_slice().into(); let indexer: Indexer = tokens.as_slice().into();

View file

@ -20,7 +20,7 @@ mod tests {
use crate::settings::flags; use crate::settings::flags;
use crate::source_code::{Indexer, Locator, Stylist}; use crate::source_code::{Indexer, Locator, Stylist};
use crate::test::test_path; use crate::test::test_path;
use crate::{directives, rustpython_helpers, settings}; use crate::{directives, settings};
#[test_case(Rule::UnusedImport, Path::new("F401_0.py"); "F401_0")] #[test_case(Rule::UnusedImport, Path::new("F401_0.py"); "F401_0")]
#[test_case(Rule::UnusedImport, Path::new("F401_1.py"); "F401_1")] #[test_case(Rule::UnusedImport, Path::new("F401_1.py"); "F401_1")]
@ -243,7 +243,7 @@ mod tests {
fn flakes(contents: &str, expected: &[Rule]) { fn flakes(contents: &str, expected: &[Rule]) {
let contents = dedent(contents); let contents = dedent(contents);
let settings = settings::Settings::for_rules(&Linter::Pyflakes); let settings = settings::Settings::for_rules(&Linter::Pyflakes);
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents); let tokens: Vec<LexResult> = ruff_rustpython::tokenize(&contents);
let locator = Locator::new(&contents); let locator = Locator::new(&contents);
let stylist = Stylist::from_contents(&contents, &locator); let stylist = Stylist::from_contents(&contents, &locator);
let indexer: Indexer = tokens.as_slice().into(); let indexer: Indexer = tokens.as_slice().into();

View file

@ -8,8 +8,9 @@ use rustpython_parser::ast::{
Suite, Withitem, Suite, Withitem,
}; };
use ruff_rustpython::vendor::{bytes, str};
use crate::source_code::stylist::{Indentation, LineEnding, Quote, Stylist}; use crate::source_code::stylist::{Indentation, LineEnding, Quote, Stylist};
use crate::vendor::{bytes, str};
mod precedence { mod precedence {
pub const ASSIGN: u8 = 3; pub const ASSIGN: u8 = 3;

View file

@ -4,13 +4,13 @@ use std::fmt;
use std::ops::Deref; use std::ops::Deref;
use once_cell::unsync::OnceCell; use once_cell::unsync::OnceCell;
use ruff_rustpython::vendor;
use rustpython_parser::ast::Location; use rustpython_parser::ast::Location;
use rustpython_parser::{lexer, Mode, Tok}; use rustpython_parser::{lexer, Mode, Tok};
use crate::ast::types::Range; use crate::ast::types::Range;
use crate::rules::pydocstyle::helpers::leading_quote; use crate::rules::pydocstyle::helpers::leading_quote;
use crate::source_code::Locator; use crate::source_code::Locator;
use crate::vendor;
pub struct Stylist<'a> { pub struct Stylist<'a> {
contents: &'a str, contents: &'a str,

View file

@ -7,12 +7,12 @@ use anyhow::Result;
use rustpython_parser::lexer::LexResult; use rustpython_parser::lexer::LexResult;
use crate::autofix::fix_file; use crate::autofix::fix_file;
use crate::directives;
use crate::linter::{check_path, LinterResult}; use crate::linter::{check_path, LinterResult};
use crate::packaging::detect_package_root; use crate::packaging::detect_package_root;
use crate::registry::Diagnostic; use crate::registry::Diagnostic;
use crate::settings::{flags, Settings}; use crate::settings::{flags, Settings};
use crate::source_code::{Indexer, Locator, Stylist}; use crate::source_code::{Indexer, Locator, Stylist};
use crate::{directives, rustpython_helpers};
pub fn test_resource_path(path: impl AsRef<Path>) -> std::path::PathBuf { pub fn test_resource_path(path: impl AsRef<Path>) -> std::path::PathBuf {
Path::new("./resources/test/").join(path) Path::new("./resources/test/").join(path)
@ -23,7 +23,7 @@ pub fn test_resource_path(path: impl AsRef<Path>) -> std::path::PathBuf {
pub fn test_path(path: &Path, settings: &Settings) -> Result<Vec<Diagnostic>> { pub fn test_path(path: &Path, settings: &Settings) -> Result<Vec<Diagnostic>> {
let path = test_resource_path("fixtures").join(path); let path = test_resource_path("fixtures").join(path);
let contents = std::fs::read_to_string(&path)?; let contents = std::fs::read_to_string(&path)?;
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents); let tokens: Vec<LexResult> = ruff_rustpython::tokenize(&contents);
let locator = Locator::new(&contents); let locator = Locator::new(&contents);
let stylist = Stylist::from_contents(&contents, &locator); let stylist = Stylist::from_contents(&contents, &locator);
let indexer: Indexer = tokens.as_slice().into(); let indexer: Indexer = tokens.as_slice().into();
@ -58,7 +58,7 @@ pub fn test_path(path: &Path, settings: &Settings) -> Result<Vec<Diagnostic>> {
let mut iterations = 0; let mut iterations = 0;
loop { loop {
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents); let tokens: Vec<LexResult> = ruff_rustpython::tokenize(&contents);
let locator = Locator::new(&contents); let locator = Locator::new(&contents);
let stylist = Stylist::from_contents(&contents, &locator); let stylist = Stylist::from_contents(&contents, &locator);
let indexer: Indexer = tokens.as_slice().into(); let indexer: Indexer = tokens.as_slice().into();

View file

@ -6,17 +6,20 @@ edition = { workspace = true }
rust-version = { workspace = true } rust-version = { workspace = true }
[dependencies] [dependencies]
ruff_formatter = { path = "../ruff_formatter" }
ruff_rustpython = { path = "../ruff_rustpython" }
ruff_text_size = { path = "../ruff_text_size" }
anyhow = { workspace = true } anyhow = { workspace = true }
clap = { workspace = true } clap = { workspace = true }
once_cell = { workspace = true } once_cell = { workspace = true }
ruff_formatter = { path = "../ruff_formatter" }
ruff_text_size = { path = "../ruff_text_size" }
rustc-hash = { workspace = true } rustc-hash = { workspace = true }
rustpython-common = { workspace = true } rustpython-common = { workspace = true }
rustpython-parser = { workspace = true } rustpython-parser = { workspace = true }
[dev-dependencies] [dev-dependencies]
ruff_testing_macros = { path = "../ruff_testing_macros" }
insta = { version = "1.19.0", features = [] } insta = { version = "1.19.0", features = [] }
test-case = { version = "2.2.2" } test-case = { version = "2.2.2" }
ruff_testing_macros = { path = "../ruff_testing_macros" } similar = { version = "2.2.1" }
similar = "2.2.1"

View file

@ -1,4 +1,3 @@
pub mod locator; pub mod locator;
pub mod rustpython_helpers;
pub mod types; pub mod types;
pub mod visitor; pub mod visitor;

View file

@ -1,28 +0,0 @@
use rustpython_parser as parser;
use rustpython_parser::ast::{Mod, Suite};
use rustpython_parser::lexer::LexResult;
use rustpython_parser::{lexer, Mode, ParseError};
/// Collect tokens up to and including the first error.
pub fn tokenize(contents: &str) -> Vec<LexResult> {
let mut tokens: Vec<LexResult> = vec![];
for tok in lexer::lex(contents, Mode::Module) {
let is_err = tok.is_err();
tokens.push(tok);
if is_err {
break;
}
}
tokens
}
/// Parse a full Python program from its tokens.
pub(crate) fn parse_program_tokens(
lxr: Vec<LexResult>,
source_path: &str,
) -> anyhow::Result<Suite, ParseError> {
parser::parse_tokens(lxr, Mode::Module, source_path).map(|top| match top {
Mod::Module { body, .. } => body,
_ => unreachable!(),
})
}

View file

@ -5,7 +5,6 @@ use rustpython_parser::lexer::LexResult;
use crate::attachment::attach; use crate::attachment::attach;
use crate::context::ASTFormatContext; use crate::context::ASTFormatContext;
use crate::core::locator::Locator; use crate::core::locator::Locator;
use crate::core::rustpython_helpers;
use crate::cst::Stmt; use crate::cst::Stmt;
use crate::newlines::normalize_newlines; use crate::newlines::normalize_newlines;
use crate::parentheses::normalize_parentheses; use crate::parentheses::normalize_parentheses;
@ -24,13 +23,13 @@ pub mod trivia;
pub fn fmt(contents: &str) -> Result<Formatted<ASTFormatContext>> { pub fn fmt(contents: &str) -> Result<Formatted<ASTFormatContext>> {
// Tokenize once. // Tokenize once.
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(contents); let tokens: Vec<LexResult> = ruff_rustpython::tokenize(contents);
// Extract trivia. // Extract trivia.
let trivia = trivia::extract_trivia_tokens(&tokens); let trivia = trivia::extract_trivia_tokens(&tokens);
// Parse the AST. // Parse the AST.
let python_ast = rustpython_helpers::parse_program_tokens(tokens, "<filename>")?; let python_ast = ruff_rustpython::parse_program_tokens(tokens, "<filename>")?;
// Convert to a CST. // Convert to a CST.
let mut python_cst: Vec<Stmt> = python_ast.into_iter().map(Into::into).collect(); let mut python_cst: Vec<Stmt> = python_ast.into_iter().map(Into::into).collect();

View file

@ -0,0 +1,14 @@
[package]
name = "ruff_rustpython"
version = "0.0.0"
publish = false
edition = { workspace = true }
rust-version = { workspace = true }
[lib]
[dependencies]
anyhow = { workspace = true }
once_cell = { workspace = true }
rustpython-common = { workspace = true }
rustpython-parser = { workspace = true }

View file

@ -3,6 +3,8 @@ use rustpython_parser::ast::{Mod, Suite};
use rustpython_parser::lexer::LexResult; use rustpython_parser::lexer::LexResult;
use rustpython_parser::{lexer, Mode, ParseError}; use rustpython_parser::{lexer, Mode, ParseError};
pub mod vendor;
/// Collect tokens up to and including the first error. /// Collect tokens up to and including the first error.
pub fn tokenize(contents: &str) -> Vec<LexResult> { pub fn tokenize(contents: &str) -> Vec<LexResult> {
let mut tokens: Vec<LexResult> = vec![]; let mut tokens: Vec<LexResult> = vec![];
@ -17,7 +19,7 @@ pub fn tokenize(contents: &str) -> Vec<LexResult> {
} }
/// Parse a full Python program from its tokens. /// Parse a full Python program from its tokens.
pub(crate) fn parse_program_tokens( pub fn parse_program_tokens(
lxr: Vec<LexResult>, lxr: Vec<LexResult>,
source_path: &str, source_path: &str,
) -> anyhow::Result<Suite, ParseError> { ) -> anyhow::Result<Suite, ParseError> {