From 6d3abdf1d67bfae472c81388205d680927f27710 Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Wed, 14 Sep 2022 01:04:13 +0200 Subject: [PATCH 1/2] feat: Implement `InvalidPrintSyntax` (`F633`) --- resources/test/fixtures/F633.py | 4 ++++ src/check_ast.rs | 24 +++++++++++++++++++++++- src/checks.rs | 7 +++++++ src/linter.rs | 25 +++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 resources/test/fixtures/F633.py diff --git a/resources/test/fixtures/F633.py b/resources/test/fixtures/F633.py new file mode 100644 index 00000000000000..3c0db17342dfb4 --- /dev/null +++ b/resources/test/fixtures/F633.py @@ -0,0 +1,4 @@ +from __future__ import print_function +import sys + +print >> sys.stderr, "Hello" diff --git a/src/check_ast.rs b/src/check_ast.rs index d905e2cc18a0a5..9de7c807fdceb0 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -3,7 +3,7 @@ use std::path::Path; use rustpython_parser::ast::{ Arg, Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, - KeywordData, Location, Stmt, StmtKind, Suite, + KeywordData, Location, Operator, Stmt, StmtKind, Suite, }; use rustpython_parser::parser; @@ -668,6 +668,28 @@ where } self.in_f_string = true; } + ExprKind::BinOp { + left, + op: Operator::RShift, + .. + } => { + if self.settings.select.contains(&CheckCode::F633) { + if let ExprKind::Name { id, .. } = &left.node { + if id == "print" { + let scope = &self.scopes + [*(self.scope_stack.last().expect("No current scope found."))]; + if let Some(Binding { + kind: BindingKind::Builtin, + .. + }) = scope.values.get("print") + { + self.checks + .push(Check::new(CheckKind::InvalidPrintSyntax, left.location)); + } + } + } + } + } ExprKind::UnaryOp { op, operand } => { let check_not_in = self.settings.select.contains(&CheckCode::E713); let check_not_is = self.settings.select.contains(&CheckCode::E714); diff --git a/src/checks.rs b/src/checks.rs index 9dc7f51cde8692..4566708efe017a 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -31,6 +31,7 @@ pub enum CheckCode { F621, F622, F631, + F633, F634, F701, F702, @@ -76,6 +77,7 @@ impl FromStr for CheckCode { "F621" => Ok(CheckCode::F621), "F622" => Ok(CheckCode::F622), "F631" => Ok(CheckCode::F631), + "F633" => Ok(CheckCode::F633), "F634" => Ok(CheckCode::F634), "F701" => Ok(CheckCode::F701), "F702" => Ok(CheckCode::F702), @@ -121,6 +123,7 @@ impl CheckCode { CheckCode::F621 => "F621", CheckCode::F622 => "F622", CheckCode::F631 => "F631", + CheckCode::F633 => "F633", CheckCode::F634 => "F634", CheckCode::F701 => "F701", CheckCode::F702 => "F702", @@ -179,6 +182,7 @@ pub enum CheckKind { FutureFeatureNotDefined(String), IOError(String), IfTuple, + InvalidPrintSyntax, ImportStarNotPermitted(String), ImportStarUsage(String), LateFutureImport, @@ -223,6 +227,7 @@ impl CheckKind { CheckKind::FutureFeatureNotDefined(_) => "FutureFeatureNotDefined", CheckKind::IOError(_) => "IOError", CheckKind::IfTuple => "IfTuple", + CheckKind::InvalidPrintSyntax => "InvalidPrintSyntax", CheckKind::ImportStarNotPermitted(_) => "ImportStarNotPermitted", CheckKind::ImportStarUsage(_) => "ImportStarUsage", CheckKind::LateFutureImport => "LateFutureImport", @@ -269,6 +274,7 @@ impl CheckKind { CheckKind::FutureFeatureNotDefined(_) => &CheckCode::F407, CheckKind::IOError(_) => &CheckCode::E902, CheckKind::IfTuple => &CheckCode::F634, + CheckKind::InvalidPrintSyntax => &CheckCode::F633, CheckKind::ImportStarNotPermitted(_) => &CheckCode::F406, CheckKind::ImportStarUsage(_) => &CheckCode::F403, CheckKind::LateFutureImport => &CheckCode::F404, @@ -335,6 +341,7 @@ impl CheckKind { format!("No such file or directory: `{name}`") } CheckKind::IfTuple => "If test is a tuple, which is always `True`".to_string(), + CheckKind::InvalidPrintSyntax => "use of >> is invalid with print function".to_string(), CheckKind::ImportStarNotPermitted(name) => { format!("`from {name} import *` only allowed at module level") } diff --git a/src/linter.rs b/src/linter.rs index d8e994ce21d2c4..ce15561e760974 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -851,6 +851,31 @@ mod tests { Ok(()) } + #[test] + fn f633() -> Result<()> { + let mut actual = check_path( + Path::new("./resources/test/fixtures/F633.py"), + &settings::Settings { + line_length: 88, + exclude: vec![], + select: BTreeSet::from([CheckCode::F633]), + }, + &fixer::Mode::Generate, + )?; + actual.sort_by_key(|check| check.location); + let expected = vec![Check { + kind: CheckKind::InvalidPrintSyntax, + location: Location::new(4, 1), + fix: None, + }]; + assert_eq!(actual.len(), expected.len()); + for i in 0..actual.len() { + assert_eq!(actual[i], expected[i]); + } + + Ok(()) + } + #[test] fn f634() -> Result<()> { let mut actual = check_path( From 800db3fb8c1567b8ae8e70953f5411dc9639a710 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 13 Sep 2022 21:09:29 -0400 Subject: [PATCH 2/2] Add to default settings + README --- README.md | 3 +- examples/generate_rules_table.rs | 3 +- pyproject.toml | 52 ++++++++++++++++++-------- resources/test/fixtures/pyproject.toml | 1 + src/pyproject.rs | 1 + src/settings.rs | 1 + 6 files changed, 44 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index a361a49af161cf..9ff57688178f25 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ ruff's goal is to achieve feature-parity with Flake8 when used (1) without any p stylistic checks; limiting to Python 3 obviates the need for certain compatibility checks.) Under those conditions, Flake8 implements about 60 rules, give or take. At time of writing, ruff -implements 38 rules. (Note that these 38 rules likely cover a disproportionate share of errors: +implements 39 rules. (Note that these 39 rules likely cover a disproportionate share of errors: unused imports, undefined variables, etc.) The unimplemented rules are tracked in #170, and include: @@ -166,6 +166,7 @@ Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis F | F621 | TooManyExpressionsInStarredAssignment | too many expressions in star-unpacking assignment | | F622 | TwoStarredExpressions | two starred expressions in assignment | | F631 | AssertTuple | Assert test is a non-empty tuple, which is always `True` | +| F633 | InvalidPrintSyntax | use of >> is invalid with print function | | F634 | IfTuple | If test is a tuple, which is always `True` | | F701 | BreakOutsideLoop | `break` outside loop | | F702 | ContinueOutsideLoop | `continue` not properly in loop | diff --git a/examples/generate_rules_table.rs b/examples/generate_rules_table.rs index 594210795fe2a6..c9444e8ada9813 100644 --- a/examples/generate_rules_table.rs +++ b/examples/generate_rules_table.rs @@ -13,13 +13,14 @@ fn main() { CheckKind::DoNotAssignLambda, CheckKind::DoNotUseBareExcept, CheckKind::DuplicateArgumentName, - CheckKind::ForwardAnnotationSyntaxError("...".to_string()), CheckKind::FStringMissingPlaceholders, + CheckKind::ForwardAnnotationSyntaxError("...".to_string()), CheckKind::FutureFeatureNotDefined("...".to_string()), CheckKind::IOError("...".to_string()), CheckKind::IfTuple, CheckKind::ImportStarNotPermitted("...".to_string()), CheckKind::ImportStarUsage("...".to_string()), + CheckKind::InvalidPrintSyntax, CheckKind::LateFutureImport, CheckKind::LineTooLong(89, 88), CheckKind::ModuleImportNotAtTopOfFile, diff --git a/pyproject.toml b/pyproject.toml index 4ae04f64cd8399..de641777338e73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,12 @@ -[project] -name = "ruff" -keywords = ["automation", "flake8", "pycodestyle", "pyflakes", "pylint", "clippy"] +[tool.poetry] +name = "autobot-ml" +version = "0.0.1" +description = "An automated code refactoring tool powered by GPT-3." +authors = ["Charlie Marsh "] +license = "MIT" +readme = "README.md" +repository = "https://github.com/charliermarsh/autobot" +keywords = ["automation", "refactor", "GPT-3"] classifiers = [ "Development Status :: 3 - Alpha", "Environment :: Console", @@ -17,19 +23,35 @@ classifiers = [ "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Quality Assurance", ] -author = "Charlie Marsh" -author_email = "charlie.r.marsh@gmail.com" -description = "An extremely fast Python linter, written in Rust." -requires-python = ">=3.7" +packages = [{ include = "autobot" }] -[project.urls] -repository = "https://github.com/charliermarsh/ruff" + +[tool.poetry.dependencies] +python = ">=3.7,<3.11" +openai = "^0.23.0" +python-dotenv = "^0.21.0" +colorama = "^0.4.5" +patch = "^1.16" +rich = "^12.5.1" + +[tool.poetry.dev-dependencies] +mypy = "^0.971" +black = "^22.8.0" +isort = "^5.10.1" + +[tool.poetry.scripts] +autobot = "autobot.main:main" [build-system] -requires = ["maturin>=0.13,<0.14"] -build-backend = "maturin" +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.black] +line-length = 88 +target-version = ["py310"] +extend-exclude = "schematics" +preview = true -[tool.maturin] -bindings = "bin" -sdist-include = ["Cargo.lock"] -strip = true +[tool.isort] +profile = "black" +extend_skip = "schematics" diff --git a/resources/test/fixtures/pyproject.toml b/resources/test/fixtures/pyproject.toml index c863b26cfd7fa5..fe7f483163495b 100644 --- a/resources/test/fixtures/pyproject.toml +++ b/resources/test/fixtures/pyproject.toml @@ -25,6 +25,7 @@ select = [ "F621", "F622", "F631", + "F633", "F634", "F701", "F702", diff --git a/src/pyproject.rs b/src/pyproject.rs index 250ce6f939ca12..29643936a6d770 100644 --- a/src/pyproject.rs +++ b/src/pyproject.rs @@ -282,6 +282,7 @@ other-attribute = 1 CheckCode::F621, CheckCode::F622, CheckCode::F631, + CheckCode::F633, CheckCode::F634, CheckCode::F701, CheckCode::F702, diff --git a/src/settings.rs b/src/settings.rs index 3fc8eac682c86c..e21cd39b1548de 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -66,6 +66,7 @@ impl Settings { CheckCode::F621, CheckCode::F622, CheckCode::F631, + CheckCode::F633, CheckCode::F634, CheckCode::F701, CheckCode::F702,