From 82eff641fb77c8972a75b3d27dbcb29e9cf40bf3 Mon Sep 17 00:00:00 2001 From: Reiner Gerecke Date: Sun, 6 Nov 2022 20:23:06 +0100 Subject: [PATCH] Remove utf-8 encoding declaration (#618) --- README.md | 5 ++-- resources/test/fixtures/U009_0.py | 3 +++ resources/test/fixtures/U009_1.py | 4 +++ resources/test/fixtures/U009_2.py | 5 ++++ resources/test/fixtures/U009_3.py | 4 +++ src/check_lines.rs | 27 +++++++++++++++++++ src/checks.rs | 13 ++++++++- src/checks_gen.rs | 6 +++++ src/linter.rs | 4 +++ .../ruff__linter__tests__U009_U009_0.py.snap | 22 +++++++++++++++ .../ruff__linter__tests__U009_U009_1.py.snap | 22 +++++++++++++++ .../ruff__linter__tests__U009_U009_2.py.snap | 6 +++++ .../ruff__linter__tests__U009_U009_3.py.snap | 6 +++++ 13 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 resources/test/fixtures/U009_0.py create mode 100644 resources/test/fixtures/U009_1.py create mode 100644 resources/test/fixtures/U009_2.py create mode 100644 resources/test/fixtures/U009_3.py create mode 100644 src/snapshots/ruff__linter__tests__U009_U009_0.py.snap create mode 100644 src/snapshots/ruff__linter__tests__U009_U009_1.py.snap create mode 100644 src/snapshots/ruff__linter__tests__U009_U009_2.py.snap create mode 100644 src/snapshots/ruff__linter__tests__U009_U009_3.py.snap diff --git a/README.md b/README.md index 568b44b9c2..7c290c7061 100644 --- a/README.md +++ b/README.md @@ -426,6 +426,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI. | U006 | UsePEP585Annotation | Use `list` instead of `List` for type annotations | 🛠 | | U007 | UsePEP604Annotation | Use `X \| Y` for type annotations | 🛠 | | U008 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` | 🛠 | +| U009 | PEP3120UnnecessaryCodingComment | utf-8 encoding declaration is unnecessary | 🛠 | ### pep8-naming @@ -606,7 +607,7 @@ including: - [`flake8-quotes`](https://pypi.org/project/flake8-quotes/) - [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/) - [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (15/32) -- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (10/34) +- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (11/34) - [`autoflake`](https://pypi.org/project/autoflake/) (1/7) Beyond rule-set parity, Ruff suffers from the following limitations vis-à-vis Flake8: @@ -630,7 +631,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl - [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (15/32) Ruff also implements the functionality that you get from [`yesqa`](https://github.com/asottile/yesqa), -and a subset of the rules implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (10/34). +and a subset of the rules implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (11/34). If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, free to file an Issue. diff --git a/resources/test/fixtures/U009_0.py b/resources/test/fixtures/U009_0.py new file mode 100644 index 0000000000..75a91b423b --- /dev/null +++ b/resources/test/fixtures/U009_0.py @@ -0,0 +1,3 @@ +# coding=utf8 + +print('Hello world') diff --git a/resources/test/fixtures/U009_1.py b/resources/test/fixtures/U009_1.py new file mode 100644 index 0000000000..90366b70ae --- /dev/null +++ b/resources/test/fixtures/U009_1.py @@ -0,0 +1,4 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +print('Hello world') diff --git a/resources/test/fixtures/U009_2.py b/resources/test/fixtures/U009_2.py new file mode 100644 index 0000000000..07cb589c8b --- /dev/null +++ b/resources/test/fixtures/U009_2.py @@ -0,0 +1,5 @@ +#!/usr/bin/python +# A coding comment is only valid in the first two lines, so this one is not checked. +# -*- coding: utf-8 -*- + +print('Hello world') diff --git a/resources/test/fixtures/U009_3.py b/resources/test/fixtures/U009_3.py new file mode 100644 index 0000000000..9353759e5e --- /dev/null +++ b/resources/test/fixtures/U009_3.py @@ -0,0 +1,4 @@ +#!/usr/bin/python +# -*- coding: something-else -*- + +print('Hello world') diff --git a/src/check_lines.rs b/src/check_lines.rs index 4e85d17bcb..5fadc51ce1 100644 --- a/src/check_lines.rs +++ b/src/check_lines.rs @@ -2,6 +2,8 @@ use std::collections::BTreeMap; +use once_cell::sync::Lazy; +use regex::Regex; use rustpython_parser::ast::Location; use crate::ast::types::Range; @@ -11,6 +13,10 @@ use crate::noqa; use crate::noqa::Directive; use crate::settings::Settings; +// Regex from PEP263 +static CODING_COMMENT_REGEX: Lazy = + Lazy::new(|| Regex::new(r"^[ \t\f]*#.*?coding[:=][ \t]*utf-?8").expect("Invalid regex")); + /// Whether the given line is too long and should be reported. fn should_enforce_line_length(line: &str, length: usize, limit: usize) -> bool { if length > limit { @@ -52,6 +58,27 @@ pub fn check_lines( .map(|lineno| lineno - 1) .unwrap_or(lineno); + if lineno < 2 { + // PEP3120 makes utf-8 the default encoding. + if CODING_COMMENT_REGEX.is_match(line) { + let line_length = line.len(); + let mut check = Check::new( + CheckKind::PEP3120UnnecessaryCodingComment, + Range { + location: Location::new(lineno + 1, 0), + end_location: Location::new(lineno + 1, line_length + 1), + }, + ); + if autofix.patch() { + check.amend(Fix::deletion( + Location::new(lineno + 1, 0), + Location::new(lineno + 1, line_length + 1), + )); + } + line_checks.push(check); + } + } + if enforce_noqa { noqa_directives .entry(noqa_lineno) diff --git a/src/checks.rs b/src/checks.rs index 53e7e0a53f..8ebfcaf577 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -124,6 +124,7 @@ pub enum CheckCode { U006, U007, U008, + U009, // pydocstyle D100, D101, @@ -365,6 +366,7 @@ pub enum CheckKind { UsePEP585Annotation(String), UsePEP604Annotation, SuperCallWithParameters, + PEP3120UnnecessaryCodingComment, // pydocstyle BlankLineAfterLastSection(String), BlankLineAfterSection(String), @@ -438,7 +440,9 @@ impl CheckCode { /// physical lines). pub fn lint_source(&self) -> &'static LintSource { match self { - CheckCode::E501 | CheckCode::W292 | CheckCode::M001 => &LintSource::Lines, + CheckCode::E501 | CheckCode::W292 | CheckCode::M001 | CheckCode::U009 => { + &LintSource::Lines + } CheckCode::Q000 | CheckCode::Q001 | CheckCode::Q002 @@ -573,6 +577,7 @@ impl CheckCode { CheckCode::U006 => CheckKind::UsePEP585Annotation("List".to_string()), CheckCode::U007 => CheckKind::UsePEP604Annotation, CheckCode::U008 => CheckKind::SuperCallWithParameters, + CheckCode::U009 => CheckKind::PEP3120UnnecessaryCodingComment, // pydocstyle CheckCode::D100 => CheckKind::PublicModule, CheckCode::D101 => CheckKind::PublicClass, @@ -750,6 +755,7 @@ impl CheckCode { CheckCode::U006 => CheckCategory::Pyupgrade, CheckCode::U007 => CheckCategory::Pyupgrade, CheckCode::U008 => CheckCategory::Pyupgrade, + CheckCode::U009 => CheckCategory::Pyupgrade, CheckCode::D100 => CheckCategory::Pydocstyle, CheckCode::D101 => CheckCategory::Pydocstyle, CheckCode::D102 => CheckCategory::Pydocstyle, @@ -918,6 +924,7 @@ impl CheckKind { CheckKind::UsePEP604Annotation => &CheckCode::U007, CheckKind::UselessObjectInheritance(_) => &CheckCode::U004, CheckKind::SuperCallWithParameters => &CheckCode::U008, + CheckKind::PEP3120UnnecessaryCodingComment => &CheckCode::U009, // pydocstyle CheckKind::BlankLineAfterLastSection(_) => &CheckCode::D413, CheckKind::BlankLineAfterSection(_) => &CheckCode::D410, @@ -1478,6 +1485,9 @@ impl CheckKind { CheckKind::ErrorSuffixOnExceptionName(name) => { format!("Exception name `{name}` should be named with an Error suffix") } + CheckKind::PEP3120UnnecessaryCodingComment => { + "utf-8 encoding declaration is unnecessary".to_string() + } // Ruff CheckKind::AmbiguousUnicodeCharacterString(confusable, representant) => { format!( @@ -1583,6 +1593,7 @@ impl CheckKind { | CheckKind::UsePEP604Annotation | CheckKind::UselessMetaclassType | CheckKind::UselessObjectInheritance(_) + | CheckKind::PEP3120UnnecessaryCodingComment | CheckKind::IsLiteral ) } diff --git a/src/checks_gen.rs b/src/checks_gen.rs index f1f24c0e43..e55bb9e8f0 100644 --- a/src/checks_gen.rs +++ b/src/checks_gen.rs @@ -230,6 +230,7 @@ pub enum CheckCodePrefix { U006, U007, U008, + U009, W, W2, W29, @@ -877,6 +878,7 @@ impl CheckCodePrefix { CheckCode::U006, CheckCode::U007, CheckCode::U008, + CheckCode::U009, ], CheckCodePrefix::U0 => vec![ CheckCode::U001, @@ -887,6 +889,7 @@ impl CheckCodePrefix { CheckCode::U006, CheckCode::U007, CheckCode::U008, + CheckCode::U009, ], CheckCodePrefix::U00 => vec![ CheckCode::U001, @@ -897,6 +900,7 @@ impl CheckCodePrefix { CheckCode::U006, CheckCode::U007, CheckCode::U008, + CheckCode::U009, ], CheckCodePrefix::U001 => vec![CheckCode::U001], CheckCodePrefix::U002 => vec![CheckCode::U002], @@ -906,6 +910,7 @@ impl CheckCodePrefix { CheckCodePrefix::U006 => vec![CheckCode::U006], CheckCodePrefix::U007 => vec![CheckCode::U007], CheckCodePrefix::U008 => vec![CheckCode::U008], + CheckCodePrefix::U009 => vec![CheckCode::U009], CheckCodePrefix::W => vec![CheckCode::W292, CheckCode::W605], CheckCodePrefix::W2 => vec![CheckCode::W292], CheckCodePrefix::W29 => vec![CheckCode::W292], @@ -1143,6 +1148,7 @@ impl CheckCodePrefix { CheckCodePrefix::U006 => PrefixSpecificity::Explicit, CheckCodePrefix::U007 => PrefixSpecificity::Explicit, CheckCodePrefix::U008 => PrefixSpecificity::Explicit, + CheckCodePrefix::U009 => PrefixSpecificity::Explicit, CheckCodePrefix::W => PrefixSpecificity::Category, CheckCodePrefix::W2 => PrefixSpecificity::Hundreds, CheckCodePrefix::W29 => PrefixSpecificity::Tens, diff --git a/src/linter.rs b/src/linter.rs index 2bced9cf83..ddd516234a 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -439,6 +439,10 @@ mod tests { #[test_case(CheckCode::U006, Path::new("U006.py"); "U006")] #[test_case(CheckCode::U007, Path::new("U007.py"); "U007")] #[test_case(CheckCode::U008, Path::new("U008.py"); "U008")] + #[test_case(CheckCode::U009, Path::new("U009_0.py"); "U009_0")] + #[test_case(CheckCode::U009, Path::new("U009_1.py"); "U009_1")] + #[test_case(CheckCode::U009, Path::new("U009_2.py"); "U009_2")] + #[test_case(CheckCode::U009, Path::new("U009_3.py"); "U009_3")] #[test_case(CheckCode::W292, Path::new("W292_0.py"); "W292_0")] #[test_case(CheckCode::W292, Path::new("W292_1.py"); "W292_1")] #[test_case(CheckCode::W292, Path::new("W292_2.py"); "W292_2")] diff --git a/src/snapshots/ruff__linter__tests__U009_U009_0.py.snap b/src/snapshots/ruff__linter__tests__U009_U009_0.py.snap new file mode 100644 index 0000000000..510e55ff78 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__U009_U009_0.py.snap @@ -0,0 +1,22 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: PEP3120UnnecessaryCodingComment + location: + row: 1 + column: 0 + end_location: + row: 1 + column: 14 + fix: + patch: + content: "" + location: + row: 1 + column: 0 + end_location: + row: 1 + column: 14 + applied: false + diff --git a/src/snapshots/ruff__linter__tests__U009_U009_1.py.snap b/src/snapshots/ruff__linter__tests__U009_U009_1.py.snap new file mode 100644 index 0000000000..0385532888 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__U009_U009_1.py.snap @@ -0,0 +1,22 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: PEP3120UnnecessaryCodingComment + location: + row: 2 + column: 0 + end_location: + row: 2 + column: 24 + fix: + patch: + content: "" + location: + row: 2 + column: 0 + end_location: + row: 2 + column: 24 + applied: false + diff --git a/src/snapshots/ruff__linter__tests__U009_U009_2.py.snap b/src/snapshots/ruff__linter__tests__U009_U009_2.py.snap new file mode 100644 index 0000000000..60c615f917 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__U009_U009_2.py.snap @@ -0,0 +1,6 @@ +--- +source: src/linter.rs +expression: checks +--- +[] + diff --git a/src/snapshots/ruff__linter__tests__U009_U009_3.py.snap b/src/snapshots/ruff__linter__tests__U009_U009_3.py.snap new file mode 100644 index 0000000000..60c615f917 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__U009_U009_3.py.snap @@ -0,0 +1,6 @@ +--- +source: src/linter.rs +expression: checks +--- +[] +