Skip to content

Commit

Permalink
Merge pull request #8 from atollk/i2023
Browse files Browse the repository at this point in the history
I2023
  • Loading branch information
atollk authored Aug 13, 2020
2 parents 13c334c + f5ce364 commit 15e44cb
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 4 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@ import os
The `import` syntax should not be used.


### I2023
When using the `import` syntax, do not duplicate module names in the `as`
segment.

```python
# Bad
import os.path as path

# Good
from os import path
import os.path as ospath
```


## `from` Syntax Errors

### I2040
Expand Down
35 changes: 32 additions & 3 deletions flake8_import_restrictions/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
2020,
2021,
2022,
2023,
2040,
2041,
2042,
Expand All @@ -32,6 +33,7 @@
2001: ["*"],
2002: ["*"],
2021: ["*"],
2023: ["*"],
2041: ["*"],
2043: ["*"],
}
Expand Down Expand Up @@ -106,6 +108,8 @@ def run(self) -> Iterable[Tuple[int, int, str, type]]:
yield from _i2021(node)
if _applies_to(node, ImportChecker.targetted_modules[2022]):
yield from _i2022(node)
if _applies_to(node, ImportChecker.targetted_modules[2023]):
yield from _i2023(node)

if isinstance(node, ast.ImportFrom):
if _applies_to(node, ImportChecker.targetted_modules[2001]):
Expand Down Expand Up @@ -133,6 +137,7 @@ def run(self) -> Iterable[Tuple[int, int, str, type]]:
2020: "Missing import alias for non-trivial import.",
2021: "Multiple imports in one import statement.",
2022: "import statements are forbidden.",
2023: "import statements with alias must not contain duplicate module names.",
2040: "Multiple imports in one from-import statement.",
2041: "from-import statements must only import modules.",
2042: "from-import statements must not import modules.",
Expand All @@ -141,12 +146,28 @@ def run(self) -> Iterable[Tuple[int, int, str, type]]:
2045: "from-import statements are forbidden.",
}

ERROR_HINTS = {
2000: "Move this import to the top of the file.",
2001: 'Choose a longer alias after the "as" keyword.',
2002: 'Remove the "as" keyword and following alias.',
2020: 'Use "as" keyword and provide a shorter alias.',
2021: "Split onto multiple lines.",
2022: 'Use "from" syntax instead.',
2023: 'Use "from" syntax instead or choose a different alias.',
2040: "Split onto multiple lines.",
2041: "Import the containing module instead.",
2042: "Import functions/classes directly instead.",
2043: "Import individual elements instead.",
2044: "Change the imported module to an absolute path.",
2045: 'Use the "import" syntax instead.',
}


def _error_tuple(error_code: int, node: ast.AST) -> Tuple[int, int, str, type]:
return (
node.lineno,
node.col_offset,
f"I{error_code} {ERROR_MESSAGES[error_code]}",
f"I{error_code} {ERROR_MESSAGES[error_code]} (hint: {ERROR_HINTS[error_code]})",
ImportChecker,
)

Expand Down Expand Up @@ -213,8 +234,7 @@ def _i2002(

def _i2020(node: ast.Import) -> Iterable[Tuple[int, int, str, type]]:
"""
When using the import syntax, if the imported module is a submodule, i.e. not a top level module, an "as" segment
should be present.
When using the import syntax, if the imported module is a submodule, i.e. not a top level module, an "as" segment should be present.
"""
for name in node.names:
if "." in name.name and not name.asname:
Expand All @@ -237,6 +257,15 @@ def _i2022(node: ast.Import) -> Iterable[Tuple[int, int, str, type]]:
yield _error_tuple(2022, node)


def _i2023(node: ast.Import) -> Iterable[Tuple[int, int, str, type]]:
"""
When using the `import` syntax, do not duplicate module names in the `as` segment.
"""
for name in node.names:
if name.name.split(".")[-1] == name.asname:
yield _error_tuple(2023, node)


def _i2040(node: ast.ImportFrom) -> Iterable[Tuple[int, int, str, type]]:
"""
When using the from syntax, the import segment only contains one import.
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = flake8-import-restrictions
version = 1.0.1
version = 1.1.0
description = A flake8 plugin used to disallow certain forms of imports.
long_description = file: README.md
long_description_content_type = text/markdown
Expand Down
27 changes: 27 additions & 0 deletions tests/test_i2023.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from tests.util import BaseTest


class Test_I2023(BaseTest):
def error_code(self) -> str:
return "I2023"

def test_pass_1(self):
code = """
from os import path
"""
result = self.run_flake8(code)
assert result == []

def test_pass_2(self):
code = """
import os.path as ospath
"""
result = self.run_flake8(code)
assert result == []

def test_fail_1(self):
code = """
import os.path as path
"""
result = self.run_flake8(code)
self.assert_error_at(result, "I2023", 1, 1)

0 comments on commit 15e44cb

Please sign in to comment.