From 1e081cf9a6909e045e1eb14bf02724ec69850b75 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 11 Mar 2023 01:06:32 -0500 Subject: [PATCH] Flag deprecated (but renamed) imports in UP035 (#3448) --- .../test/fixtures/pyupgrade/UP035.py | 2 +- crates/ruff/src/checkers/ast/mod.rs | 4 +- crates/ruff/src/codes.rs | 2 +- crates/ruff/src/registry.rs | 2 +- crates/ruff/src/rules/pyupgrade/mod.rs | 2 +- ...t_replacements.rs => deprecated_import.rs} | 275 ++++++++++++------ crates/ruff/src/rules/pyupgrade/rules/mod.rs | 4 +- ...ff__rules__pyupgrade__tests__UP035.py.snap | 80 +++-- 8 files changed, 250 insertions(+), 121 deletions(-) rename crates/ruff/src/rules/pyupgrade/rules/{import_replacements.rs => deprecated_import.rs} (59%) diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP035.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP035.py index 688e3fd6de..d26f99eb07 100644 --- a/crates/ruff/resources/test/fixtures/pyupgrade/UP035.py +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP035.py @@ -41,7 +41,7 @@ if True: Good, ) -from typing import Callable, Match, Pattern, List, OrderedDict +from typing import Callable, Match, Pattern, List, OrderedDict, AbstractSet if True: from collections import ( Mapping, Counter) diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index a85226bcc9..62b3eba6d3 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -1138,8 +1138,8 @@ where if self.settings.rules.enabled(&Rule::RewriteCElementTree) { pyupgrade::rules::replace_c_element_tree(self, stmt); } - if self.settings.rules.enabled(&Rule::ImportReplacements) { - pyupgrade::rules::import_replacements( + if self.settings.rules.enabled(&Rule::DeprecatedImport) { + pyupgrade::rules::deprecated_import( self, stmt, names, diff --git a/crates/ruff/src/codes.rs b/crates/ruff/src/codes.rs index 9addd828ff..2c91ccd32d 100644 --- a/crates/ruff/src/codes.rs +++ b/crates/ruff/src/codes.rs @@ -373,7 +373,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option { (Pyupgrade, "032") => Rule::FString, (Pyupgrade, "033") => Rule::FunctoolsCache, (Pyupgrade, "034") => Rule::ExtraneousParentheses, - (Pyupgrade, "035") => Rule::ImportReplacements, + (Pyupgrade, "035") => Rule::DeprecatedImport, (Pyupgrade, "036") => Rule::OutdatedVersionBlock, (Pyupgrade, "037") => Rule::QuotedAnnotation, (Pyupgrade, "038") => Rule::IsinstanceWithTuple, diff --git a/crates/ruff/src/registry.rs b/crates/ruff/src/registry.rs index cf7686de81..19e8db7f9d 100644 --- a/crates/ruff/src/registry.rs +++ b/crates/ruff/src/registry.rs @@ -339,7 +339,7 @@ ruff_macros::register_rules!( rules::pyupgrade::rules::FString, rules::pyupgrade::rules::FunctoolsCache, rules::pyupgrade::rules::ExtraneousParentheses, - rules::pyupgrade::rules::ImportReplacements, + rules::pyupgrade::rules::DeprecatedImport, rules::pyupgrade::rules::OutdatedVersionBlock, rules::pyupgrade::rules::QuotedAnnotation, rules::pyupgrade::rules::IsinstanceWithTuple, diff --git a/crates/ruff/src/rules/pyupgrade/mod.rs b/crates/ruff/src/rules/pyupgrade/mod.rs index d4e1cbd10f..9bfcf7ffd8 100644 --- a/crates/ruff/src/rules/pyupgrade/mod.rs +++ b/crates/ruff/src/rules/pyupgrade/mod.rs @@ -59,7 +59,7 @@ mod tests { #[test_case(Rule::FString, Path::new("UP032.py"); "UP032")] #[test_case(Rule::FunctoolsCache, Path::new("UP033.py"); "UP033")] #[test_case(Rule::ExtraneousParentheses, Path::new("UP034.py"); "UP034")] - #[test_case(Rule::ImportReplacements, Path::new("UP035.py"); "UP035")] + #[test_case(Rule::DeprecatedImport, Path::new("UP035.py"); "UP035")] #[test_case(Rule::OutdatedVersionBlock, Path::new("UP036_0.py"); "UP036_0")] #[test_case(Rule::OutdatedVersionBlock, Path::new("UP036_1.py"); "UP036_1")] #[test_case(Rule::OutdatedVersionBlock, Path::new("UP036_2.py"); "UP036_2")] diff --git a/crates/ruff/src/rules/pyupgrade/rules/import_replacements.rs b/crates/ruff/src/rules/pyupgrade/rules/deprecated_import.rs similarity index 59% rename from crates/ruff/src/rules/pyupgrade/rules/import_replacements.rs rename to crates/ruff/src/rules/pyupgrade/rules/deprecated_import.rs index ad477c5d35..3e0a3e14ff 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/import_replacements.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/deprecated_import.rs @@ -12,28 +12,68 @@ use crate::registry::Rule; use crate::rules::pyupgrade::fixes; use crate::settings::types::PythonVersion; -#[violation] -pub struct ImportReplacements { - pub module: String, - pub members: Vec, - pub fixable: bool, +/// An import was moved and renamed as part of a deprecation. +/// For example, `typing.AbstractSet` was moved to `collections.abc.Set`. +#[derive(Debug, PartialEq, Eq)] +struct WithRename { + module: String, + member: String, + target: String, } -impl Violation for ImportReplacements { +/// A series of imports from the same module were moved to another module, +/// but retain their original names. +#[derive(Debug, PartialEq, Eq)] +struct WithoutRename { + target: String, + members: Vec, + fixable: bool, +} + +#[derive(Debug, PartialEq, Eq)] +enum Deprecation { + WithRename(WithRename), + WithoutRename(WithoutRename), +} + +#[violation] +pub struct DeprecatedImport { + deprecation: Deprecation, +} + +impl Violation for DeprecatedImport { const AUTOFIX: Option = Some(AutofixKind::new(Availability::Sometimes)); #[derive_message_formats] fn message(&self) -> String { - let ImportReplacements { - module, members, .. - } = self; - let names = members.iter().map(|name| format!("`{name}`")).join(", "); - format!("Import from `{module}` instead: {names}") + match &self.deprecation { + Deprecation::WithoutRename(WithoutRename { + members, target, .. + }) => { + let names = members.iter().map(|name| format!("`{name}`")).join(", "); + format!("Import from `{target}` instead: {names}") + } + Deprecation::WithRename(WithRename { + module, + member, + target, + }) => { + format!("`{module}.{member}` is deprecated, use `{target}` instead") + } + } } fn autofix_title_formatter(&self) -> Option String> { - self.fixable - .then_some(|ImportReplacements { module, .. }| format!("Import from `{module}`")) + if let Deprecation::WithoutRename(WithoutRename { fixable, .. }) = self.deprecation { + fixable.then_some(|DeprecatedImport { deprecation }| { + let Deprecation::WithoutRename(WithoutRename { target, .. }) = deprecation else { + unreachable!(); + }; + format!("Import from `{target}`") + }) + } else { + None + } } } @@ -47,7 +87,7 @@ const RELEVANT_MODULES: &[&str] = &[ "typing.re", ]; -// Members of `collections` that have been moved to `collections.abc`. +// Members of `collections` that were moved to `collections.abc`. const COLLECTIONS_TO_ABC: &[&str] = &[ "AsyncGenerator", "AsyncIterable", @@ -76,10 +116,10 @@ const COLLECTIONS_TO_ABC: &[&str] = &[ "ValuesView", ]; -// Members of `pipes` that have been moved to `shlex`. +// Members of `pipes` that were moved to `shlex`. const PIPES_TO_SHLEX: &[&str] = &["quote"]; -// Members of `typing_extensions` that have been moved to `typing`. +// Members of `typing_extensions` that were moved to `typing`. const TYPING_EXTENSIONS_TO_TYPING: &[&str] = &[ "AsyncIterable", "AsyncIterator", @@ -96,10 +136,10 @@ const TYPING_EXTENSIONS_TO_TYPING: &[&str] = &[ // Python 3.7+ -// Members of `mypy_extensions` that have been moved to `typing`. +// Members of `mypy_extensions` that were moved to `typing`. const MYPY_EXTENSIONS_TO_TYPING_37: &[&str] = &["NoReturn"]; -// Members of `typing_extensions` that have been moved to `typing`. +// Members of `typing_extensions` that were moved to `typing`. const TYPING_EXTENSIONS_TO_TYPING_37: &[&str] = &[ "AsyncContextManager", "AsyncGenerator", @@ -111,10 +151,10 @@ const TYPING_EXTENSIONS_TO_TYPING_37: &[&str] = &[ // Python 3.8+ -// Members of `mypy_extensions` that have been moved to `typing`. +// Members of `mypy_extensions` that were moved to `typing`. const MYPY_EXTENSIONS_TO_TYPING_38: &[&str] = &["TypedDict"]; -// Members of `typing_extensions` that have been moved to `typing`. +// Members of `typing_extensions` that were moved to `typing`. const TYPING_EXTENSIONS_TO_TYPING_38: &[&str] = &[ "Final", "Literal", @@ -126,7 +166,7 @@ const TYPING_EXTENSIONS_TO_TYPING_38: &[&str] = &[ // Python 3.9+ -// Members of `typing` that have been moved to `collections.abc`. +// Members of `typing` that were moved to `collections.abc`. const TYPING_TO_COLLECTIONS_ABC_39: &[&str] = &[ "AsyncGenerator", "AsyncIterable", @@ -153,24 +193,41 @@ const TYPING_TO_COLLECTIONS_ABC_39: &[&str] = &[ "ValuesView", ]; -// Members of `typing` that have been moved to `collections`. +// Members of `typing` that were moved to `collections`. const TYPING_TO_COLLECTIONS_39: &[&str] = &["ChainMap", "Counter", "OrderedDict"]; -// Members of `typing` that have been moved to `typing.re`. +// Members of `typing` that were moved to `typing.re`. const TYPING_TO_RE_39: &[&str] = &["Match", "Pattern"]; -// Members of `typing.re` that have been moved to `re`. +// Members of `typing.re` that were moved to `re`. const TYPING_RE_TO_RE_39: &[&str] = &["Match", "Pattern"]; -// Members of `typing_extensions` that have been moved to `typing`. +// Members of `typing_extensions` that were moved to `typing`. const TYPING_EXTENSIONS_TO_TYPING_39: &[&str] = &["Annotated", "get_type_hints"]; +// Members of `typing` that were moved _and_ renamed (and thus cannot be +// automatically fixed). +const TYPING_TO_RENAME_PY39: &[(&str, &str)] = &[ + ( + "AsyncContextManager", + "contextlib.AbstractAsyncContextManager", + ), + ("AbstractSet", "collections.abc.Set"), + ("Tuple", "tuple"), + ("List", "list"), + ("FrozenSet", "frozenset"), + ("Dict", "dict"), + ("Set", "set"), + ("Deque", "collections.deque"), + ("DefaultDict", "collections.defaultdict"), +]; + // Python 3.10+ -// Members of `typing` that have been moved to `collections.abc`. +// Members of `typing` that were moved to `collections.abc`. const TYPING_TO_COLLECTIONS_ABC_310: &[&str] = &["Callable"]; -// Members of `typing_extensions` that have been moved to `typing`. +// Members of `typing_extensions` that were moved to `typing`. const TYPING_EXTENSIONS_TO_TYPING_310: &[&str] = &[ "Concatenate", "ParamSpecArgs", @@ -184,7 +241,7 @@ const TYPING_EXTENSIONS_TO_TYPING_310: &[&str] = &[ // Python 3.11+ -// Members of `typing_extensions` that have been moved to `typing`. +// Members of `typing_extensions` that were moved to `typing`. const TYPING_EXTENSIONS_TO_TYPING_311: &[&str] = &[ "Any", "LiteralString", @@ -205,12 +262,6 @@ const TYPING_EXTENSIONS_TO_TYPING_311: &[&str] = &[ "reveal_type", ]; -struct Replacement<'a> { - module: &'a str, - members: Vec<&'a AliasData>, - content: Option, -} - struct ImportReplacer<'a> { stmt: &'a Stmt, module: &'a str, @@ -239,17 +290,43 @@ impl<'a> ImportReplacer<'a> { } } - fn replacements(&self) -> Vec { - let mut replacements = vec![]; + /// Return a list of deprecated imports whose members were renamed. + fn with_renames(&self) -> Vec { + let mut operations = vec![]; + if self.module == "typing" { + if self.version >= PythonVersion::Py39 { + for member in self.members { + if let Some(target) = TYPING_TO_RENAME_PY39.iter().find_map(|(name, target)| { + if member.name == *name { + Some(*target) + } else { + None + } + }) { + operations.push(WithRename { + module: "typing".to_string(), + member: member.name.to_string(), + target: target.to_string(), + }); + } + } + } + } + operations + } + + /// Return a list of deprecated imports whose members were moved, but not renamed. + fn without_renames(&self) -> Vec<(WithoutRename, Option)> { + let mut operations = vec![]; match self.module { "collections" => { - if let Some(replacement) = self.try_replace(COLLECTIONS_TO_ABC, "collections.abc") { - replacements.push(replacement); + if let Some(operation) = self.try_replace(COLLECTIONS_TO_ABC, "collections.abc") { + operations.push(operation); } } "pipes" => { - if let Some(replacement) = self.try_replace(PIPES_TO_SHLEX, "shlex") { - replacements.push(replacement); + if let Some(operation) = self.try_replace(PIPES_TO_SHLEX, "shlex") { + operations.push(operation); } } "typing_extensions" => { @@ -269,9 +346,8 @@ impl<'a> ImportReplacer<'a> { if self.version >= PythonVersion::Py311 { typing_extensions_to_typing.extend(TYPING_EXTENSIONS_TO_TYPING_311); } - if let Some(replacement) = self.try_replace(&typing_extensions_to_typing, "typing") - { - replacements.push(replacement); + if let Some(operation) = self.try_replace(&typing_extensions_to_typing, "typing") { + operations.push(operation); } } "mypy_extensions" => { @@ -282,8 +358,8 @@ impl<'a> ImportReplacer<'a> { if self.version >= PythonVersion::Py38 { mypy_extensions_to_typing.extend(MYPY_EXTENSIONS_TO_TYPING_38); } - if let Some(replacement) = self.try_replace(&mypy_extensions_to_typing, "typing") { - replacements.push(replacement); + if let Some(operation) = self.try_replace(&mypy_extensions_to_typing, "typing") { + operations.push(operation); } } "typing" => { @@ -295,10 +371,10 @@ impl<'a> ImportReplacer<'a> { if self.version >= PythonVersion::Py310 { typing_to_collections_abc.extend(TYPING_TO_COLLECTIONS_ABC_310); } - if let Some(replacement) = + if let Some(operation) = self.try_replace(&typing_to_collections_abc, "collections.abc") { - replacements.push(replacement); + operations.push(operation); } // `typing` to `collections` @@ -306,8 +382,8 @@ impl<'a> ImportReplacer<'a> { if self.version >= PythonVersion::Py39 { typing_to_collections.extend(TYPING_TO_COLLECTIONS_39); } - if let Some(replacement) = self.try_replace(&typing_to_collections, "collections") { - replacements.push(replacement); + if let Some(operation) = self.try_replace(&typing_to_collections, "collections") { + operations.push(operation); } // `typing` to `re` @@ -315,21 +391,29 @@ impl<'a> ImportReplacer<'a> { if self.version >= PythonVersion::Py39 { typing_to_re.extend(TYPING_TO_RE_39); } - if let Some(replacement) = self.try_replace(&typing_to_re, "re") { - replacements.push(replacement); + if let Some(operation) = self.try_replace(&typing_to_re, "re") { + operations.push(operation); } } "typing.re" if self.version >= PythonVersion::Py39 => { - if let Some(replacement) = self.try_replace(TYPING_RE_TO_RE_39, "re") { - replacements.push(replacement); + if let Some(operation) = self.try_replace(TYPING_RE_TO_RE_39, "re") { + operations.push(operation); } } _ => {} } - replacements + operations } - fn try_replace(&'a self, candidates: &[&str], target: &'a str) -> Option> { + fn try_replace( + &'a self, + candidates: &[&str], + target: &'a str, + ) -> Option<(WithoutRename, Option)> { + if candidates.is_empty() { + return None; + } + let (matched_names, unmatched_names) = self.partition_imports(candidates); // If we have no matched names, we don't need to do anything. @@ -339,11 +423,16 @@ impl<'a> ImportReplacer<'a> { if unmatched_names.is_empty() { let matched = ImportReplacer::format_import_from(&matched_names, target); - Some(Replacement { - module: target, - members: matched_names, - content: Some(matched), - }) + let operation = WithoutRename { + target: target.to_string(), + members: matched_names + .iter() + .map(|name| name.name.to_string()) + .collect(), + fixable: true, + }; + let fix = Some(matched); + Some((operation, fix)) } else { let indentation = indentation(self.locator, self.stmt); @@ -351,11 +440,16 @@ impl<'a> ImportReplacer<'a> { // line, we can't add a statement after it. For example, if we have // `if True: import foo`, we can't add a statement to the next line. let Some(indentation) = indentation else { - return Some(Replacement { - module: target, - members: matched_names, - content: None, - }); + let operation = WithoutRename { + target: target.to_string(), + members: matched_names + .iter() + .map(|name| name.name.to_string()) + .collect(), + fixable: false, + }; + let fix = None; + return Some((operation, fix)); }; let matched = ImportReplacer::format_import_from(&matched_names, target); @@ -367,15 +461,20 @@ impl<'a> ImportReplacer<'a> { .collect::>(), ); - Some(Replacement { - module: target, - members: matched_names, - content: Some(format!( - "{unmatched}{}{}{matched}", - self.stylist.line_ending().as_str(), - indentation, - )), - }) + let operation = WithoutRename { + target: target.to_string(), + members: matched_names + .iter() + .map(|name| name.name.to_string()) + .collect(), + fixable: true, + }; + let fix = Some(format!( + "{unmatched}{}{}{matched}", + self.stylist.line_ending().as_str(), + indentation, + )); + Some((operation, fix)) } } @@ -410,7 +509,7 @@ impl<'a> ImportReplacer<'a> { } /// UP035 -pub fn import_replacements( +pub fn deprecated_import( checker: &mut Checker, stmt: &Stmt, names: &[Alias], @@ -442,21 +541,15 @@ pub fn import_replacements( checker.settings.target_version, ); - for replacement in fixer.replacements() { + for (operation, fix) in fixer.without_renames() { let mut diagnostic = Diagnostic::new( - ImportReplacements { - module: replacement.module.to_string(), - members: replacement - .members - .iter() - .map(|name| name.name.to_string()) - .collect(), - fixable: replacement.content.is_some(), + DeprecatedImport { + deprecation: Deprecation::WithoutRename(operation), }, Range::from(stmt), ); - if checker.patch(&Rule::ImportReplacements) { - if let Some(content) = replacement.content { + if checker.patch(&Rule::DeprecatedImport) { + if let Some(content) = fix { diagnostic.amend(Fix::replacement( content, stmt.location, @@ -466,4 +559,14 @@ pub fn import_replacements( } checker.diagnostics.push(diagnostic); } + + for operation in fixer.with_renames() { + let diagnostic = Diagnostic::new( + DeprecatedImport { + deprecation: Deprecation::WithRename(operation), + }, + Range::from(stmt), + ); + checker.diagnostics.push(diagnostic); + } } diff --git a/crates/ruff/src/rules/pyupgrade/rules/mod.rs b/crates/ruff/src/rules/pyupgrade/rules/mod.rs index a50fd8ac67..8e18ed986d 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/mod.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/mod.rs @@ -5,12 +5,12 @@ pub(crate) use convert_typed_dict_functional_to_class::{ convert_typed_dict_functional_to_class, ConvertTypedDictFunctionalToClass, }; pub(crate) use datetime_utc_alias::{datetime_utc_alias, DatetimeTimezoneUTC}; +pub(crate) use deprecated_import::{deprecated_import, DeprecatedImport}; pub(crate) use deprecated_unittest_alias::{deprecated_unittest_alias, DeprecatedUnittestAlias}; pub(crate) use extraneous_parentheses::{extraneous_parentheses, ExtraneousParentheses}; pub(crate) use f_strings::{f_strings, FString}; pub(crate) use format_literals::{format_literals, FormatLiterals}; pub(crate) use functools_cache::{functools_cache, FunctoolsCache}; -pub(crate) use import_replacements::{import_replacements, ImportReplacements}; pub(crate) use lru_cache_without_parameters::{ lru_cache_without_parameters, LRUCacheWithoutParameters, }; @@ -46,12 +46,12 @@ pub(crate) use useless_object_inheritance::{useless_object_inheritance, UselessO mod convert_named_tuple_functional_to_class; mod convert_typed_dict_functional_to_class; mod datetime_utc_alias; +mod deprecated_import; mod deprecated_unittest_alias; mod extraneous_parentheses; mod f_strings; mod format_literals; mod functools_cache; -mod import_replacements; mod lru_cache_without_parameters; mod native_literals; mod open_alias; diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP035.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP035.py.snap index 348d81677b..5c830bafe1 100644 --- a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP035.py.snap +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP035.py.snap @@ -3,7 +3,7 @@ source: crates/ruff/src/rules/pyupgrade/mod.rs expression: diagnostics --- - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -23,7 +23,7 @@ expression: diagnostics column: 31 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -43,7 +43,7 @@ expression: diagnostics column: 38 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`, `Sequence`" suggestion: "Import from `collections.abc`" fixable: true @@ -63,7 +63,7 @@ expression: diagnostics column: 41 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -83,7 +83,7 @@ expression: diagnostics column: 40 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -103,7 +103,7 @@ expression: diagnostics column: 42 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -123,7 +123,7 @@ expression: diagnostics column: 33 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -143,7 +143,7 @@ expression: diagnostics column: 32 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`, `Sequence`" suggestion: "Import from `collections.abc`" fixable: true @@ -163,7 +163,7 @@ expression: diagnostics column: 50 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -183,7 +183,7 @@ expression: diagnostics column: 51 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -203,7 +203,7 @@ expression: diagnostics column: 44 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -223,7 +223,7 @@ expression: diagnostics column: 44 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -243,7 +243,7 @@ expression: diagnostics column: 40 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: "Import from `collections.abc`" fixable: true @@ -263,7 +263,7 @@ expression: diagnostics column: 40 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`, `Callable`" suggestion: "Import from `collections.abc`" fixable: true @@ -283,7 +283,7 @@ expression: diagnostics column: 5 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections.abc` instead: `Callable`" suggestion: "Import from `collections.abc`" fixable: true @@ -292,18 +292,18 @@ expression: diagnostics column: 0 end_location: row: 44 - column: 62 + column: 75 fix: - content: "from typing import Match, Pattern, List, OrderedDict\nfrom collections.abc import Callable" + content: "from typing import Match, Pattern, List, OrderedDict, AbstractSet\nfrom collections.abc import Callable" location: row: 44 column: 0 end_location: row: 44 - column: 62 + column: 75 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `collections` instead: `OrderedDict`" suggestion: "Import from `collections`" fixable: true @@ -312,18 +312,18 @@ expression: diagnostics column: 0 end_location: row: 44 - column: 62 + column: 75 fix: - content: "from typing import Callable, Match, Pattern, List\nfrom collections import OrderedDict" + content: "from typing import Callable, Match, Pattern, List, AbstractSet\nfrom collections import OrderedDict" location: row: 44 column: 0 end_location: row: 44 - column: 62 + column: 75 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport body: "Import from `re` instead: `Match`, `Pattern`" suggestion: "Import from `re`" fixable: true @@ -332,18 +332,44 @@ expression: diagnostics column: 0 end_location: row: 44 - column: 62 + column: 75 fix: - content: "from typing import Callable, List, OrderedDict\nfrom re import Match, Pattern" + content: "from typing import Callable, List, OrderedDict, AbstractSet\nfrom re import Match, Pattern" location: row: 44 column: 0 end_location: row: 44 - column: 62 + column: 75 parent: ~ - kind: - name: ImportReplacements + name: DeprecatedImport + body: "`typing.List` is deprecated, use `list` instead" + suggestion: ~ + fixable: false + location: + row: 44 + column: 0 + end_location: + row: 44 + column: 75 + fix: ~ + parent: ~ +- kind: + name: DeprecatedImport + body: "`typing.AbstractSet` is deprecated, use `collections.abc.Set` instead" + suggestion: ~ + fixable: false + location: + row: 44 + column: 0 + end_location: + row: 44 + column: 75 + fix: ~ + parent: ~ +- kind: + name: DeprecatedImport body: "Import from `collections.abc` instead: `Mapping`" suggestion: ~ fixable: false