flake8-type-checking 2.3.0__tar.gz → 2.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flake8_type_checking-2.3.0 → flake8_type_checking-2.4.0}/PKG-INFO +4 -3
- {flake8_type_checking-2.3.0 → flake8_type_checking-2.4.0}/README.md +1 -1
- {flake8_type_checking-2.3.0 → flake8_type_checking-2.4.0}/flake8_type_checking/checker.py +9 -2
- {flake8_type_checking-2.3.0 → flake8_type_checking-2.4.0}/flake8_type_checking/plugin.py +5 -4
- {flake8_type_checking-2.3.0 → flake8_type_checking-2.4.0}/pyproject.toml +2 -1
- flake8_type_checking-2.3.0/setup.py +0 -38
- {flake8_type_checking-2.3.0 → flake8_type_checking-2.4.0}/LICENSE +0 -0
- {flake8_type_checking-2.3.0 → flake8_type_checking-2.4.0}/flake8_type_checking/__init__.py +0 -0
- {flake8_type_checking-2.3.0 → flake8_type_checking-2.4.0}/flake8_type_checking/constants.py +0 -0
- {flake8_type_checking-2.3.0 → flake8_type_checking-2.4.0}/flake8_type_checking/py.typed +0 -0
- {flake8_type_checking-2.3.0 → flake8_type_checking-2.4.0}/flake8_type_checking/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: flake8-type-checking
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: A flake8 plugin for managing type-checking imports & forward references
|
|
5
5
|
Home-page: https://github.com/snok
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -21,11 +21,12 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.10
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
25
|
Classifier: Programming Language :: Python :: 3.8
|
|
25
26
|
Classifier: Programming Language :: Python :: 3.9
|
|
26
27
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
27
28
|
Classifier: Typing :: Typed
|
|
28
|
-
Requires-Dist: astor; python_version < "3.9"
|
|
29
|
+
Requires-Dist: astor ; python_version < "3.9"
|
|
29
30
|
Requires-Dist: classify-imports
|
|
30
31
|
Requires-Dist: flake8
|
|
31
32
|
Project-URL: Repository, https://github.com/snok/flake8-type-checking
|
|
@@ -253,7 +254,7 @@ Enabling dependency support will also enable FastAPI and Pydantic support.
|
|
|
253
254
|
- **type**: `bool`
|
|
254
255
|
```ini
|
|
255
256
|
[flake8]
|
|
256
|
-
type-checking-fastapi-dependency-support-enabled
|
|
257
|
+
type-checking-fastapi-dependency-support-enabled = true # default false
|
|
257
258
|
```
|
|
258
259
|
|
|
259
260
|
### Cattrs support
|
|
@@ -219,7 +219,7 @@ Enabling dependency support will also enable FastAPI and Pydantic support.
|
|
|
219
219
|
- **type**: `bool`
|
|
220
220
|
```ini
|
|
221
221
|
[flake8]
|
|
222
|
-
type-checking-fastapi-dependency-support-enabled
|
|
222
|
+
type-checking-fastapi-dependency-support-enabled = true # default false
|
|
223
223
|
```
|
|
224
224
|
|
|
225
225
|
### Cattrs support
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import ast
|
|
4
|
+
import fnmatch
|
|
4
5
|
import os
|
|
5
6
|
from ast import Index, literal_eval
|
|
6
7
|
from contextlib import suppress
|
|
@@ -547,6 +548,12 @@ class ImportVisitor(DunderAllMixin, AttrsMixin, FastAPIMixin, PydanticMixin, ast
|
|
|
547
548
|
|
|
548
549
|
# -- Map imports -------------------------------
|
|
549
550
|
|
|
551
|
+
def is_exempt_module(self, module_name: str) -> bool:
|
|
552
|
+
"""Template module name check."""
|
|
553
|
+
return any(
|
|
554
|
+
{exempt_module for exempt_module in self.exempt_modules if fnmatch.fnmatch(module_name, exempt_module)}
|
|
555
|
+
)
|
|
556
|
+
|
|
550
557
|
def add_import(self, node: Import) -> None: # noqa: C901
|
|
551
558
|
"""Add relevant ast objects to import lists."""
|
|
552
559
|
if self.in_type_checking_block(node):
|
|
@@ -562,12 +569,12 @@ class ImportVisitor(DunderAllMixin, AttrsMixin, FastAPIMixin, PydanticMixin, ast
|
|
|
562
569
|
return None
|
|
563
570
|
|
|
564
571
|
# Skip checking the import if the module is passlisted.
|
|
565
|
-
if isinstance(node, ast.ImportFrom) and node.module
|
|
572
|
+
if isinstance(node, ast.ImportFrom) and node.module and self.is_exempt_module(node.module):
|
|
566
573
|
return
|
|
567
574
|
|
|
568
575
|
for name_node in node.names:
|
|
569
576
|
# Skip checking the import if the module is passlisted
|
|
570
|
-
if isinstance(node, ast.Import) and name_node.name
|
|
577
|
+
if isinstance(node, ast.Import) and self.is_exempt_module(name_node.name):
|
|
571
578
|
return
|
|
572
579
|
|
|
573
580
|
# Look for a TYPE_CHECKING import
|
|
@@ -88,14 +88,15 @@ class Plugin:
|
|
|
88
88
|
|
|
89
89
|
def run(self) -> Flake8Generator:
|
|
90
90
|
"""Run flake8 plugin and return any relevant errors."""
|
|
91
|
+
# disable plugin for stub files
|
|
92
|
+
# context: https://github.com/snok/flake8-type-checking/issues/152
|
|
93
|
+
if self.filename.endswith('.pyi'):
|
|
94
|
+
return
|
|
95
|
+
|
|
91
96
|
visitor = TypingOnlyImportsChecker(self.tree, self.options)
|
|
92
97
|
|
|
93
98
|
for e in visitor.errors:
|
|
94
99
|
code = e[2].split(':')[0]
|
|
95
|
-
if self.filename.endswith('.pyi') and code.startswith('TC100'):
|
|
96
|
-
# Stub files don't need futures imports
|
|
97
|
-
# context: https://github.com/snok/flake8-type-checking/issues/121
|
|
98
|
-
continue
|
|
99
100
|
if self.should_warn(code):
|
|
100
101
|
yield e
|
|
101
102
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = 'flake8-type-checking'
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.4.0"
|
|
4
4
|
description = 'A flake8 plugin for managing type-checking imports & forward references'
|
|
5
5
|
homepage = 'https://github.com/snok'
|
|
6
6
|
repository = 'https://github.com/snok/flake8-type-checking'
|
|
@@ -21,6 +21,7 @@ classifiers = [
|
|
|
21
21
|
'Programming Language :: Python :: 3.9',
|
|
22
22
|
'Programming Language :: Python :: 3.10',
|
|
23
23
|
'Programming Language :: Python :: 3.11',
|
|
24
|
+
'Programming Language :: Python :: 3.12',
|
|
24
25
|
'Typing :: Typed',
|
|
25
26
|
]
|
|
26
27
|
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
from setuptools import setup
|
|
3
|
-
|
|
4
|
-
packages = \
|
|
5
|
-
['flake8_type_checking']
|
|
6
|
-
|
|
7
|
-
package_data = \
|
|
8
|
-
{'': ['*']}
|
|
9
|
-
|
|
10
|
-
install_requires = \
|
|
11
|
-
['classify-imports', 'flake8']
|
|
12
|
-
|
|
13
|
-
extras_require = \
|
|
14
|
-
{':python_version < "3.9"': ['astor']}
|
|
15
|
-
|
|
16
|
-
entry_points = \
|
|
17
|
-
{'flake8.extension': ['TC = flake8_type_checking.plugin:Plugin']}
|
|
18
|
-
|
|
19
|
-
setup_kwargs = {
|
|
20
|
-
'name': 'flake8-type-checking',
|
|
21
|
-
'version': '2.3.0',
|
|
22
|
-
'description': 'A flake8 plugin for managing type-checking imports & forward references',
|
|
23
|
-
'long_description': '[](https://pypi.org/project/flake8-type-checking/)\n[](https://codecov.io/gh/sondrelg/flake8-type-checking)\n[](https://github.com/snok/flake8-type-checking/actions/workflows/testing.yml)\n[](https://pypi.org/project/flake8-type-checking/)\n[](http://mypy-lang.org/)\n\n# flake8-type-checking\n\nLets you know which imports to move in or out of\n[type-checking](https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING) blocks.\n\nThe plugin assumes that the imports you only use for type hinting\n*are not* required at runtime. When imports aren\'t strictly required at runtime, it means we can guard them.\n\nGuarding imports provides 3 major benefits:\n\n- 🔧 It reduces import circularity issues,\n- 🧹 It organizes imports, and\n- 🚀 It completely eliminates the overhead of type hint imports at runtime\n\n<br>\n\nEssentially, this code:\n\n```python\nimport pandas # 15mb library\n\nx: pandas.DataFrame\n```\n\nbecomes this:\n\n```python\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n import pandas # <-- no longer imported at runtime\n\nx: "pandas.DataFrame"\n```\n\nMore examples can be found in the [examples](#examples) section.\n\n<br>\n\nIf you\'re using [pydantic](https://pydantic-docs.helpmanual.io/),\n[fastapi](https://fastapi.tiangolo.com/), or [cattrs](https://github.com/python-attrs/cattrs)\nsee the [configuration](#configuration) for how to enable support.\n\n## Primary features\n\nThe plugin will:\n\n- Tell you when an import should be moved into a type-checking block\n- Tell you when an import should be moved out again\n\nAnd depending on which error code range you\'ve opted into, it will tell you\n\n- Whether you need to add a `from __future__ import annotations` import\n- Whether you need to quote an annotation\n- Whether you can unquote a quoted annotation\n\n## Error codes\n\n| Code | Description |\n|-------|------------------------------------------------------------------------------------|\n| TC001 | Move application import into a type-checking block |\n| TC002 | Move third-party import into a type-checking block |\n| TC003 | Move built-in import into a type-checking block |\n| TC004 | Move import out of type-checking block. Import is used for more than type hinting. |\n| TC005 | Found empty type-checking block |\n| TC006 | Annotation in typing.cast() should be a string literal |\n\n## Choosing how to handle forward references\n\nYou need to choose whether to opt-into using the\n`TC100`- or the `TC200`-range of error codes.\n\nThey represent two different ways of solving the same problem, so please only choose one.\n\n`TC100` and `TC101` manage forward references by taking advantage of\n[postponed evaluation of annotations](https://www.python.org/dev/peps/pep-0563/).\n\n| Code | Description |\n|-------|-----------------------------------------------------|\n| TC100 | Add \'from \\_\\_future\\_\\_ import annotations\' import |\n| TC101 | Annotation does not need to be a string literal |\n\n`TC200` and `TC201` manage forward references using [string literals](https://www.python.org/dev/peps/pep-0484/#forward-references).\n\n| Code | Description |\n|-------|-----------------------------------------------------|\n| TC200 | Annotation needs to be made into a string literal |\n| TC201 | Annotation does not need to be a string literal |\n\n## Enabling error ranges\n\nAdd `TC` and `TC1` or `TC2` to your flake8 config like this:\n\n```ini\n[flake8]\nmax-line-length = 80\nmax-complexity = 12\n...\nignore = E501\n# You can use \'extend-select\' (new in flake8 v4):\nextend-select = TC, TC2\n# OR \'select\':\nselect = C,E,F..., TC, TC2 # or TC1\n# OR \'enable-extensions\':\nenable-extensions = TC, TC2 # or TC1\n```\n\nIf you are unsure which `TC` range to pick, see the [rationale](#rationale) for more info.\n\n## Installation\n\n```shell\npip install flake8-type-checking\n```\n\n## Configuration\n\nThese options are configurable, and can be set in your flake8 config.\n\n### Exempt modules\n\nIf you wish to exempt certain modules from\nneeding to be moved into type-checking blocks, you can specify which\nmodules to ignore.\n\n- **setting name**: `type-checking-exempt-modules`\n- **type**: `list`\n\n```ini\n[flake8]\ntype-checking-exempt-modules = typing_extensions # default []\n```\n\n### Strict\n\nThe plugin, by default, will report TC00[1-3] errors\nfor imports if there aren\'t already other imports from the same module.\nWhen there are other imports from the same module,\nthe import circularity and performance benefits no longer\napply from guarding an import.\n\nWhen strict mode is enabled, the plugin will flag all\nimports that *can* be moved.\n\n- **setting name**: `type-checking-strict`\n- **type**: `bool`\n\n```ini\n[flake8]\ntype-checking-strict = true # default false\n```\n\n### Pydantic support\n\nIf you use Pydantic models in your code, you should enable Pydantic support.\nThis will treat any class variable annotation as being needed during runtime.\n\n- **name**: `type-checking-pydantic-enabled`\n- **type**: `bool`\n```ini\n[flake8]\ntype-checking-pydantic-enabled = true # default false\n```\n### Pydantic support base-class passlist\n\nDisabling checks for all class annotations is a little aggressive.\n\nIf you feel comfortable that all base classes named, e.g., `NamedTuple` are *not* Pydantic models,\nthen you can pass the names of the base classes in this setting, to re-enable checking for classes\nwhich inherit from them.\n\n- **name**: `type-checking-pydantic-enabled-baseclass-passlist`\n- **type**: `list`\n```ini\n[flake8]\ntype-checking-pydantic-enabled-baseclass-passlist = NamedTuple, TypedDict # default []\n```\n\n### FastAPI support\n\nIf you\'re using the plugin for a FastAPI project,\nyou should enable support. This will treat the annotations\nof any decorated function as needed at runtime.\n\nEnabling FastAPI support will also enable Pydantic support.\n\n- **name**: `type-checking-fastapi-enabled`\n- **type**: `bool`\n```ini\n[flake8]\ntype-checking-fastapi-enabled = true # default false\n```\n\nOne more thing to note for FastAPI users is that dependencies\n(functions used in `Depends`) will produce false positives, unless\nyou enable dependency support as described below.\n\n### FastAPI dependency support\n\nIn addition to preventing false positives for decorators, we *can*\nprevent false positives for dependencies. We are making a pretty bad\ntrade-off however: by enabling this option we treat every annotation\nin every function definition across your entire project as a possible\ndependency annotation. In other words, we stop linting all function\nannotations completely, to avoid the possibility of false positives.\nIf you prefer to be on the safe side, you should enable this - otherwise\nit might be enough to be aware that false positives can happen for functions\nused as dependencies.\n\nEnabling dependency support will also enable FastAPI and Pydantic support.\n\n- **name**: `type-checking-fastapi-dependency-support-enabled`\n- **type**: `bool`\n```ini\n[flake8]\ntype-checking-fastapi-dependency-support-enabled: true # default false\n```\n\n### Cattrs support\n\nIf you\'re using the plugin in a project which uses `cattrs`,\nyou can enable support. This will treat the annotations\nof any decorated `attrs` class as needed at runtime, since\n`cattrs.unstructure` calls will fail when loading\nclasses where types are not available at runtime.\n\nNote: the cattrs support setting does not yet detect and\nignore class var annotations on dataclasses or other non-attrs class types.\nThis can be added in the future if needed.\n\n- **name**: `type-checking-cattrs-enabled`\n- **type**: `bool`\n```ini\n[flake8]\ntype-checking-cattrs-enabled = true # default false\n```\n\n## Rationale\n\nWhy did we create this plugin?\n\nGood type hinting typically requires a lot of project imports, which can increase\nthe risk of [import cycles](https://mypy.readthedocs.io/en/stable/runtime_troubles.html?#import-cycles)\nin a project. The recommended way of preventing this problem is to use `typing.TYPE_CHECKING` blocks\nto guard these types of imports. In particular, `TC001` helps protect against this issue.\n\nOnce imports are guarded, they will no longer be evaluated/imported during runtime. The\nconsequence of this is that these imports can no longer be treated as if they\nwere imported outside the block. Instead we need to use [forward references](https://www.python.org/dev/peps/pep-0484/#forward-references).\n\nFor Python version `>= 3.7`, there are actually two ways of solving this issue.\nYou can either make your annotations string literals, or you can use a `__futures__` import to enable [postponed evaluation of annotations](https://www.python.org/dev/peps/pep-0563/).\nSee [this](https://stackoverflow.com/a/55344418/8083459) excellent stackoverflow answer\nfor a great explanation of the differences.\n\n## Examples\n\n<details>\n<summary><b>Performance example</b></summary>\n\nImports for type hinting can have a performance impact.\n\n```python\nimport pandas\n\n\ndef dataframe_length(df: pandas.DataFrame) -> int:\n return len(df)\n```\n\nIn this example, we import a 15mb library, for a single type hint.\n\nWe don\'t need to perform this operation at runtime, *at all*.\nIf we know that the import will not otherwise be needed by surrounding code,\nwe can simply guard it, like this:\n\n```python\nfrom typing import TYPE_CHECKING\n\n\nif TYPE_CHECKING:\n import pandas # <-- no longer imported at runtime\n\n\ndef dataframe_length(df: "pandas.DataFrame") -> int:\n return len(df)\n```\n\nNow the import is no longer made at runtime. If you\'re unsure about how this works, see the [mypy docs](https://mypy.readthedocs.io/en/stable/runtime_troubles.html?#typing-type-checking) for a basic introduction.\n</details>\n\n<details>\n<summary><b>Import circularity example</b></summary>\n\n**Bad code**\n\n`models/a.py`\n```python\nfrom models.b import B\n\nclass A(Model):\n def foo(self, b: B): ...\n```\n\n`models/b.py`\n```python\nfrom models.a import A\n\nclass B(Model):\n def bar(self, a: A): ...\n```\n\nWill result in these errors\n\n```shell\n>> a.py: TC002 Move third-party import \'models.b.B\' into a type-checking block\n>> b.py: TC002 Move third-party import \'models.a.A\' into a type-checking block\n```\n\nand consequently trigger these errors if imports are purely moved into type-checking block, without proper forward reference handling\n\n```shell\n>> a.py: TC100 Add \'from __future__ import annotations\' import\n>> b.py: TC100 Add \'from __future__ import annotations\' import\n```\n\nor\n\n```shell\n>> a.py: TC200 Annotation \'B\' needs to be made into a string literal\n>> b.py: TC200 Annotation \'A\' needs to be made into a string literal\n```\n\n**Good code**\n\n`models/a.py`\n```python\n# TC1\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n from models.b import B\n\nclass A(Model):\n def foo(self, b: B): ...\n```\nor\n```python\n# TC2\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n from models.b import B\n\nclass A(Model):\n def foo(self, b: \'B\'): ...\n```\n\n`models/b.py`\n```python\n# TC1\nfrom __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n from models.a import A\n\nclass B(Model):\n def bar(self, a: A): ...\n```\n\nor\n\n```python\n# TC2\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n from models.a import A\n\nclass B(Model):\n def bar(self, a: \'A\'): ...\n```\n</details>\n\n<details>\n<summary><b>Examples from the wild</b></summary>\n\nHere are a few examples of public projects that use `flake8-type-checking`:\n\n- [Example from the Poetry codebase](https://github.com/python-poetry/poetry/blob/714c09dd845c58079cff3f3cbedc114dff2194c9/src/poetry/factory.py#L1:L33)\n- [Example from the asgi-correlation-id codebase](https://github.com/snok/asgi-correlation-id/blob/main/asgi_correlation_id/middleware.py#L1:L12)\n\n</details>\n\n## Running the plugin as a pre-commit hook\n\nYou can run this flake8 plugin as a [pre-commit](https://github.com/pre-commit/pre-commit) hook:\n\n```yaml\n- repo: https://github.com/pycqa/flake8\n rev: 4.0.1\n hooks:\n - id: flake8\n additional_dependencies:\n - flake8-type-checking\n```\n\n## Contributing\n\nPlease feel free to open an issue or a PR 👏\n',
|
|
24
|
-
'author': 'Sondre Lillebø Gundersen',
|
|
25
|
-
'author_email': 'sondrelg@live.no',
|
|
26
|
-
'maintainer': 'None',
|
|
27
|
-
'maintainer_email': 'None',
|
|
28
|
-
'url': 'https://github.com/snok',
|
|
29
|
-
'packages': packages,
|
|
30
|
-
'package_data': package_data,
|
|
31
|
-
'install_requires': install_requires,
|
|
32
|
-
'extras_require': extras_require,
|
|
33
|
-
'entry_points': entry_points,
|
|
34
|
-
'python_requires': '>=3.8',
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
setup(**setup_kwargs)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|