Skip to content

Commit

Permalink
Python 3.7 support dropped & Improved Type Comment Analysis (#311)
Browse files Browse the repository at this point in the history
  • Loading branch information
hakancelikdev authored Dec 22, 2023
1 parent 5a0dccb commit 9c60870
Show file tree
Hide file tree
Showing 46 changed files with 135 additions and 304 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v3.5.3

Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repos:
- id: isort

- repo: https://github.com/hakancelikdev/unimport
rev: 1.1.0
rev: 1.2.0
hooks:
- id: unimport

Expand Down
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ inputs:
runs:
using: "composite"
steps:
- run: pip install --upgrade pip && python -m pip install unimport==1.1.0
- run: pip install --upgrade pip && python -m pip install unimport==1.2.0
shell: bash
- run: unimport --color auto --gitignore --ignore-init ${{ inputs.extra_args }}
shell: bash
Expand Down
23 changes: 22 additions & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,32 @@ All notable changes to this project will be documented in this file.

## [Unreleased] - YYYY-MM-DD

## [1.2.0] - 2023-12-03
## [1.2.0] - 2023-12-22

### Changed

- Python 3.6 support dropped
- Python 3.7 support dropped

### Fixed

- Improved Type Comment Analysis

> To ensure accurate type comment analysis, a crucial fix was implemented in the code.
> The update involves refining the process by adding a check within ast.AnnAssign and
> ast.arg types. Specifically, the code now includes a verification that
> visit_Constant occurs under an annotation, addressing unnecessary name discovery
> issues for better accuracy in type_comment assessment.
```python
import sys
from typing import (
List,
)


test_list: List[str] = ["spam", "eggs"] # it thought spam and eggs were a ast.Name object.
```

## [1.1.0] - 2023-11-17

Expand Down
8 changes: 4 additions & 4 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ $ git rebase upstream/main

## Testing

First, make sure you have at least one of the python versions py3.7, py3.8, py3.9,
py3.10 and py3.11. If not all versions are available, after opening PR, github action
will run the tests for each version, so you can be sure that you wrote the correct code.
You can skip the tox step below.
First, make sure you have at least one of the python versions py3.8, py3.9, py3.10 and
py3.11. If not all versions are available, after opening PR, github action will run the
tests for each version, so you can be sure that you wrote the correct code. You can skip
the tox step below.

After typing your codes, you should run the tests by typing the following command.

Expand Down
113 changes: 0 additions & 113 deletions docs/FAQ.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ process with Unimport.

- **Documentation** https://unimport.hakancelik.dev/
- **Issues** https://github.com/hakancelikdev/unimport/issues/
- **Changelog** https://unimport.hakancelik.dev/1.1.0/CHANGELOG/
- **Changelog** https://unimport.hakancelik.dev/1.2.0/CHANGELOG/
- **Playground** https://playground-unimport.hakancelik.dev/
2 changes: 1 addition & 1 deletion docs/installation.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Unimport requires Python 3.7+ and can be easily installed using most common Python
Unimport requires Python 3.8+ and can be easily installed using most common Python
packaging tools. We recommend installing the latest stable release from PyPI with pip:

```shell
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial/other-useful-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ from x import ( # noqa
)
```

**If version of your python is 3.8+** Unimport support multiple skip like below. _It
doesn't matter which line you put the comment on._
Unimport support multiple skip like below. _It doesn't matter which line you put the
comment on._

```python
from package import (
Expand Down
4 changes: 1 addition & 3 deletions docs/tutorial/supported-behaviors.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ def test(arg: "List['Dict']") -> None:

#### Comments

**This feature is only available for python 3.8.**

Imports in the example below aren't flag as unused by import.
Imports in the example below aren't flag as unused by unimport.

```python
from typing import Any
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorial/use-with-github-action.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- uses: actions/checkout@v3.5.3
- uses: actions/setup-python@v4.6.1
- name: Check unused imports
uses: hakancelikdev/unimport@1.1.0
uses: hakancelikdev/unimport@1.2.0
with:
extra_args: --include src/
```
3 changes: 1 addition & 2 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ site_url: https://unimport.hakancelik.dev
repo_url: https://github.com/hakancelikdev/unimport
repo_name: hakancelikdev/unimport
edit_uri: https://github.com/hakancelikdev/unimport/tree/main/docs
copyright: Copyright © 2020 - 2023 Hakan Çelik
copyright: Copyright © 2019 - 2024 Hakan Çelik

markdown_extensions:
- fenced_code
Expand Down Expand Up @@ -132,4 +132,3 @@ nav:
- Contributing: CONTRIBUTING.md
- Changelog: CHANGELOG.md
- Authors: AUTHORS.md
- FAQ: FAQ.md
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ skip_gitignore = true

[tool.black]
line-length = 120
target-version = ['py37', 'py38', 'py39', 'py310']
target-version = ['py38', 'py39', 'py310', 'py311']

[tool.unimport]
include_star_import = true
Expand Down
9 changes: 3 additions & 6 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ classifiers =
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Expand All @@ -29,10 +28,10 @@ classifiers =
project_urls =
Documentation = https://unimport.hakancelik.dev/
Issues = https://github.com/hakancelikdev/unimport/issues/
Changelog = https://unimport.hakancelik.dev/1.1.0/CHANGELOG/
Changelog = https://unimport.hakancelik.dev/1.2.0/CHANGELOG/

[options]
python_requires = >=3.7, <3.12
python_requires = >=3.8, <3.12
include_package_data = true
zip_safe = true
packages =
Expand All @@ -46,10 +45,8 @@ install_requires =
libcst>=0.3.7, <=1.1.0; python_version == '3.10'
libcst>=0.3.7, <=1.1.0; python_version == '3.9'
libcst>=0.3.0, <=1.1.0; python_version == '3.8'
libcst>=0.3.0, <=1.0.1; python_version == '3.7'
pathspec>=0.10.1, <1; python_version >= '3.7'
pathspec>=0.10.1, <1
toml>=0.9.0, <1
typing-extensions>=3.7.4, <4; python_version < '3.8'

[options.entry_points]
console_scripts =
Expand Down
2 changes: 1 addition & 1 deletion src/unimport/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = "1.1.0"
__version__ = "1.2.0"
__description__ = "A linter, formatter for finding and removing unused import statements."
7 changes: 1 addition & 6 deletions src/unimport/analyzers/decarators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import re
from typing import cast

from unimport import constants as C
from unimport import typing as T

__all__ = ("generic_visit", "skip_import")
Expand All @@ -22,11 +21,7 @@ def skip_import(func: T.FunctionT) -> T.FunctionT:

@functools.wraps(func)
def wrapper(self, node, *args, **kwargs):
if C.PY38_PLUS:
source_segment = "\n".join(self.source.splitlines()[node.lineno - 1 : node.end_lineno])
else:
source_segment = self.source.splitlines()[node.lineno - 1]

source_segment = "\n".join(self.source.splitlines()[node.lineno - 1 : node.end_lineno])
skip_comment = bool(re.search(SKIP_IMPORT_COMMENTS_REGEX, source_segment, re.IGNORECASE))
if not any((skip_comment, self.any_import_error)):
func(self, node, *args, **kwargs)
Expand Down
29 changes: 12 additions & 17 deletions src/unimport/analyzers/importable.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import ast
from typing import FrozenSet, List

from unimport import constants as C
from unimport import typing as T
Expand All @@ -18,17 +19,14 @@ class ImportableAnalyzer(ast.NodeVisitor):
)

def __init__(self) -> None:
self.importable_nodes: List[T.ASTNameType] = [] # nodes on the __all__ list
self.suggestions_nodes: List[T.ASTImportableT] = [] # nodes on the CFN
self.importable_nodes: list[ast.Constant] = [] # nodes on the __all__ list
self.suggestions_nodes: list[T.ASTImportableT] = [] # nodes on the CFN

def traverse(self, tree):
self.visit(tree)

for node in self.importable_nodes:
if isinstance(node, ast.Constant):
Name.register(lineno=node.lineno, name=str(node.value), node=node, is_all=True)
elif isinstance(node, ast.Str):
Name.register(lineno=node.lineno, name=node.s, node=node, is_all=True)
Name.register(lineno=node.lineno, name=node.value, node=node, is_all=True)

self.clear()

Expand Down Expand Up @@ -61,7 +59,7 @@ def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
def visit_Assign(self, node: ast.Assign) -> None:
if getattr(node.targets[0], "id", None) == "__all__" and isinstance(node.value, (ast.List, ast.Tuple, ast.Set)):
for item in node.value.elts:
if isinstance(item, (ast.Constant, ast.Str)):
if isinstance(item, ast.Constant) and isinstance(item.value, str):
self.importable_nodes.append(item)

for target in node.targets: # we only get assigned names
Expand All @@ -78,18 +76,18 @@ def visit_Expr(self, node: ast.Expr) -> None:
):
if node.value.func.attr == "append":
for arg in node.value.args:
if isinstance(arg, (ast.Constant, ast.Str)):
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
self.importable_nodes.append(arg)

elif node.value.func.attr == "extend":
for arg in node.value.args:
if isinstance(arg, ast.List):
for item in arg.elts:
if isinstance(item, (ast.Constant, ast.Str)):
if isinstance(item, ast.Constant) and isinstance(item.value, str):
self.importable_nodes.append(item)

@classmethod
def get_names(cls, package: str) -> FrozenSet[str]:
def get_names(cls, package: str) -> frozenset[str]:
if utils.is_std(package):
return utils.get_dir(package)

Expand All @@ -106,16 +104,13 @@ def get_names(cls, package: str) -> FrozenSet[str]:
return visitor.get_all() or visitor.get_suggestion()
return frozenset()

def get_all(self) -> FrozenSet[str]:
def get_all(self) -> frozenset[str]:
names = set()
for node in self.importable_nodes:
if isinstance(node, ast.Constant):
names.add(node.value)
elif isinstance(node, ast.Str):
names.add(node.s)
names.add(node.value)
return frozenset(names)

def get_suggestion(self) -> FrozenSet[str]:
def get_suggestion(self) -> frozenset[str]:
names = set()
for node in self.suggestions_nodes: # type: ignore
if isinstance(node, ast.Name):
Expand Down
Loading

0 comments on commit 9c60870

Please sign in to comment.