Flake8 plugin for managing type-checking imports & forward references

Overview
Package version Code coverage Test status Supported Python versions Checked with mypy

flake8-type-checking

Lets you know which imports to put in type-checking blocks.

For the imports you've already defined inside type-checking blocks, it can also help you manage forward references using PEP 484 or PEP 563 style references.

Codes

Code Description
TC001 Move import into a type-checking block
TC002 Move third-party import into a type-checking block
TC003 Found multiple type checking blocks
TC004 Move import out of type-checking block. Import is used for more than type hinting.
TC005 Empty type-checking block

Forward reference codes

These code ranges are opt-in. They represent two different ways of solving the same problem, so please only choose one.

TC100 and TC101 manage forward references by taking advantage of postponed evaluation of annotations.

Code Description
TC100 Add 'from __future__ import annotations' import
TC101 Annotation does not need to be a string literal

TC200 and TC201 manage forward references using string literals.

Code Description
TC200 Annotation needs to be made into a string literal
TC201 Annotation does not need to be a string literal

To select one of the ranges, just specify the code in your flake8 config:

[flake8]
max-line-length = 80
max-complexity = 12
...
ignore = E501
select = C,E,F,W,..., TC, TC2  # or TC1
# alternatively:
enable-extensions = TC, TC2  # or TC1

Configuration

The plugin currently only has one setting:

  • type-checking-exempt-modules: Specify a list of modules to ignore TC001/TC002 errors from. Could be useful if you, e.g., want to handle big libraries, but prefer not to handle typing imports.

Rationale

Good type hinting requires a lot of imports, which can increase the risk of import cycles in your project. The recommended way of preventing this problem is to use typing.TYPE_CHECKING blocks to guard these types of imports.

Both TC001 and TC002 help alleviate this problem; the reason there are two codes instead of one, is because the import cycles rarely occur from library/third-party imports, so this artificial split provides a way to filter down the total pool of imports for users that want to guard against import cycles, but don't want to manage every import in their projects this strictly.

Once imports are guarded, they will no longer be evaluated during runtime. The consequence of this is that these imports can no longer be treated as if they were imported outside the block. Instead we need to use forward references.

For Python version >= 3.7, there are actually two ways of solving this issue. You can either make your annotations string literals, or you can use a __futures__ import to enable postponed evaluation of annotations. See this excellent stackoverflow answer for a better explanation of the differences.

Installation

pip install flake8-type-checking

Examples

Bad code

models/a.py

from models.b import B

class A(Model):
    def foo(self, b: B): ...

models/b.py

from models.a import A

class B(Model):
    def bar(self, a: A): ...

Will result in these errors

>> a.py: TC002 Move third-party import 'models.b.B' into a type-checking block
>> b.py: TC002 Move third-party import 'models.a.A' into a type-checking block

and consequently trigger these errors if imports are purely moved into type-checking block, without proper forward reference handling

>> a.py: TC100 Add 'from __future__ import annotations' import
>> b.py: TC100 Add 'from __future__ import annotations' import

or

>> a.py: TC200 Annotation 'B' needs to be made into a string literal
>> b.py: TC200 Annotation 'A' needs to be made into a string literal

Good code

models/a.py

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from models.b import B

class A(Model):
    def foo(self, b: 'B'): ...

models/b.py

# TC1
from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from models.a import A

class B(Model):
    def bar(self, a: A): ...

or

# TC2
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from models.a import A

class B(Model):
    def bar(self, a: 'A'): ...

As a pre-commit hook

You can run this flake8 plugin as a pre-commit hook:

- repo: https://github.com/pycqa/flake8
  rev: 3.9.2
  hooks:
    - id: flake8
      additional_dependencies: [ flake8-type-checking ]
Comments
  • TB running flake8 with flake8-type-checking installed

    TB running flake8 with flake8-type-checking installed

    Factoids:

    • Fedora 33

    • Python 3.9.2

    • flake8 3.8.4

    • flake8 --version (non-apology; I have a linter fetish):

      3.8.4 (assertive: 1.3.0, dlint: 0.11.0, flake-mutable: 1.2.0, flake8-bandit: 2.1.2, flake8-bugbear: 20.11.1,
      flake8-cognitive-complexity: 0.1.0, flake8-comprehensions: 3.3.1, flake8-eradicate: 1.0.0,
      flake8-expression-complexity: 0.0.9, flake8-fixme: 1.1.1, flake8-mock: 0.3, flake8-pie: 0.7.1,
      flake8-pytest-style: 1.4.1, flake8-return: 1.1.2, flake8-type-checking: 1.0.0, flake8_builtins: 1.5.2,
      flake8_multiline_containers: 0.0.18, flake8_simplify: 0.14.0, flake8_typing_imports: 1.10.1,
      mccabe: 0.6.1, pycodestyle: 2.6.0, pyflakes: 2.2.0) CPython 3.9.2 on Linux
      

    Let me know if more info is needed.

    ⌜10:22⌟ 🐚 flake8
    multiprocessing.pool.RemoteTraceback: 
    """
    Traceback (most recent call last):
      File "/usr/lib64/python3.9/multiprocessing/pool.py", line 125, in worker
        result = (True, func(*args, **kwds))
      File "/usr/lib64/python3.9/multiprocessing/pool.py", line 48, in mapstar
        return list(map(*args))
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8/checker.py", line 676, in _run_checks
        return checker.run_checks()
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8/checker.py", line 589, in run_checks
        self.run_ast_checks()
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8/checker.py", line 494, in run_ast_checks
        for (line_number, offset, text, _) in runner:
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8_type_checking/plugin.py", line 37, in run
        visitor = TypingOnlyImportsChecker(self._tree)
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8_type_checking/checker.py", line 348, in __init__
        self.visitor.visit(node)
      File "/usr/lib64/python3.9/ast.py", line 407, in visit
        return visitor(node)
      File "/usr/lib64/python3.9/ast.py", line 483, in generic_visit
        value = self.visit(value)
      File "/usr/lib64/python3.9/ast.py", line 407, in visit
        return visitor(node)
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8_type_checking/checker.py", line 332, in visit_FunctionDef
        self.generic_visit(node)
      File "/usr/lib64/python3.9/ast.py", line 483, in generic_visit
        value = self.visit(value)
      File "/usr/lib64/python3.9/ast.py", line 407, in visit
        return visitor(node)
      File "/usr/lib64/python3.9/ast.py", line 483, in generic_visit
        value = self.visit(value)
      File "/usr/lib64/python3.9/ast.py", line 407, in visit
        return visitor(node)
      File "/usr/lib64/python3.9/ast.py", line 483, in generic_visit
        value = self.visit(value)
      File "/usr/lib64/python3.9/ast.py", line 407, in visit
        return visitor(node)
      File "/usr/lib64/python3.9/ast.py", line 492, in generic_visit
        new_node = self.visit(old_value)
      File "/usr/lib64/python3.9/ast.py", line 407, in visit
        return visitor(node)
      File "/usr/lib64/python3.9/ast.py", line 492, in generic_visit
        new_node = self.visit(old_value)
      File "/usr/lib64/python3.9/ast.py", line 407, in visit
        return visitor(node)
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8_type_checking/checker.py", line 291, in visit_Attribute
        node = self._set_child_node_attribute(node, ATTRIBUTE_PROPERTY, node.attr)
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8_type_checking/checker.py", line 275, in _set_child_node_attribute
        setattr(node.__dict__[key], attr, val)
    AttributeError: 'NoneType' object has no attribute 'flake8-type-checking_parent'
    """
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
      File "/home/$USER/.local/bin/flake8", line 8, in <module>
        sys.exit(main())
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8/main/cli.py", line 22, in main
        app.run(argv)
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8/main/application.py", line 363, in run
        self._run(argv)
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8/main/application.py", line 351, in _run
        self.run_checks()
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8/main/application.py", line 264, in run_checks
        self.file_checker_manager.run()
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8/checker.py", line 321, in run
        self.run_parallel()
      File "/home/$USER/.local/lib/python3.9/site-packages/flake8/checker.py", line 287, in run_parallel
        for ret in pool_map:
      File "/usr/lib64/python3.9/multiprocessing/pool.py", line 448, in <genexpr>
        return (item for chunk in result for item in chunk)
      File "/usr/lib64/python3.9/multiprocessing/pool.py", line 870, in next
        raise value
    AttributeError: 'NoneType' object has no attribute 'flake8-type-checking_parent'
    
    opened by ben-alkov 18
  • TC100 not needed for stub files

    TC100 not needed for stub files

    flake8-pyi has started reporting the following warning if from __future__ import annotations is in a stub file:

    Y044 "from __future__ import annotations" has no effect in stub files.

    This is because forward references are enabled by default.

    It might be a good idea for TC100 to not be reported against stub files?

    opened by jonyscathe 15
  • Support pydantic and fastapi

    Support pydantic and fastapi

    Hello,

    pydantic and fastapi make use of typehints during runtime. Because flake8-type-checking doesn't know this, it leads to false recommendations to move typehints into the type-checking block.

    Example pydantic:

    model.py

    from typing import Optional
    
    from pydantic import BaseModel
    
    from pydantic import EmailStr
    
    
    class Payload(BaseModel):
        id: Optional[int]
        text: str
        email: EmailStr
    
    flake8 model.py
    model.py:5:1: TC002 Move third-party import 'pydantic.EmailStr' into a type-checking block
    

    Moving the import to the type-checking block and quote the usages leads to this error when pydantic tries to initialize an object:

    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "pydantic/main.py", line 404, in pydantic.main.BaseModel.__init__
      File "pydantic/main.py", line 1040, in pydantic.main.validate_model
      File "pydantic/fields.py", line 699, in pydantic.fields.ModelField.validate
    pydantic.errors.ConfigError: field "email" not yet prepared so type is still a ForwardRef, you might need to call Payload.update_forward_refs().
    

    Example fastapi

    api.py:

    import uvicorn
    from fastapi import FastAPI
    
    from model import Payload
    
    app = FastAPI()
    
    
    @app.post("/my_endpoint")
    async def get_endpoint(payload: Payload):
        return None
    
    
    if __name__ == "__main__":
        uvicorn.run(app)
    
    flake8 api.py
    api.py:4:1: TC002 Move third-party import 'model.Payload' into a type-checking block
    

    Moving the import to the type-checking block and quote the usages leads to this error when when running the api:

    Traceback (most recent call last):
      File "/home/finswimmer/tmp/minimal-fastapi/minimal_fastapi/example_api.py", line 13, in <module>
        async def get_endpoint(payload: "Payload"):
      File "/home/finswimmer/tmp/minimal-fastapi/.venv/lib/python3.8/site-packages/fastapi/routing.py", line 582, in decorator
        self.add_api_route(
      File "/home/finswimmer/tmp/minimal-fastapi/.venv/lib/python3.8/site-packages/fastapi/routing.py", line 525, in add_api_route
        route = route_class(
      File "/home/finswimmer/tmp/minimal-fastapi/.venv/lib/python3.8/site-packages/fastapi/routing.py", line 407, in __init__
        self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
      File "/home/finswimmer/tmp/minimal-fastapi/.venv/lib/python3.8/site-packages/fastapi/dependencies/utils.py", line 278, in get_dependant
        endpoint_signature = get_typed_signature(call)
      File "/home/finswimmer/tmp/minimal-fastapi/.venv/lib/python3.8/site-packages/fastapi/dependencies/utils.py", line 248, in get_typed_signature
        typed_params = [
      File "/home/finswimmer/tmp/minimal-fastapi/.venv/lib/python3.8/site-packages/fastapi/dependencies/utils.py", line 253, in <listcomp>
        annotation=get_typed_annotation(param, globalns),
      File "/home/finswimmer/tmp/minimal-fastapi/.venv/lib/python3.8/site-packages/fastapi/dependencies/utils.py", line 265, in get_typed_annotation
        annotation = evaluate_forwardref(annotation, globalns, globalns)
      File "pydantic/typing.py", line 62, in pydantic.typing.evaluate_forwardref
        'MutableSet',
      File "/usr/lib/python3.8/typing.py", line 518, in _evaluate
        eval(self.__forward_code__, globalns, localns),
      File "<string>", line 1, in <module>
    NameError: name 'Payload' is not defined
    

    Any chance to handle this at least for pydantic and fastapi out of the box, as they are widely-used? (I've no idea if there would be a generic way). Of course using # noqa is always an option, but depending on the size of the application this might be a lot of work.

    Thanks a lot for this super useful plugin :+1:

    fin swimmer

    opened by finswimmer 12
  • Strange F821 false positive on flake8 git main

    Strange F821 false positive on flake8 git main

    When using this extension with PyCQA/[email protected], it triggers false F821 errors from pyflakes. The error does not happen with flake8 4.0.1 from PyPI. It only seems to happen on top-level code, ~~and goes away if a non-empty TYPE_CHECKING block with any import (even an unused one) is present~~.

    Minimal working example

    import os
    
    os.urandom(8)
    

    pyproject.toml:

    [tool.poetry]
    name = "test"
    version = "0.1.0"
    description = ""
    authors = ["nyuszika7h <[email protected]>"]
    
    [tool.poetry.dependencies]
    python = "^3.10"
    
    [tool.poetry.dev-dependencies]
    flake8 = {git = "https://github.com/PyCQA/flake8.git", rev = "main"}
    flake8-type-checking = "^1.3.1"
    
    [build-system]
    requires = ["poetry-core>=1.0.0"]
    build-backend = "poetry.core.masonry.api"
    

    flake8 output:

    ❯ flake8 test.py
    test.py:3:1: F821 undefined name 'os'
    

    ~~The following does not trigger the error:~~

    import os                                               
    from typing import TYPE_CHECKING                        
                                                            
    if TYPE_CHECKING:                                       
        import sys  # random import to demonstrate, not used
                                                            
    os.urandom(8)                                           
    
    opened by 0xallie 10
  • Colon after code causes issue

    Colon after code causes issue

    Due to the fact that several tools are involved in this problem, I am not 100% sure that the problem is here, but at least I think so. 😉

    I'll try to describe the complete use case:

    We don't like that imports from typing are forced into a type checking block so they need to be quoted (see https://github.com/python-poetry/poetry/issues/4776#issuecomment-971331270). (Maybe, something to discuss in another issue. 😉)

    Thus, we add # noqa: TC002 to such imports. So far, so good.

    However, yesqa keeps removing these noqa comments. At first, I thought this to be an issue of yesqa. So, I debugged it. And it turns out that yesqa is calling flake8 --format=%(code)s <myfile>.

    For example, if you run this on a file with the following content

    from typing import List
    
    
    def f(a: List[int]):
        myDict = {1 + 1 : 2}
        print(myDict)
        print(a)
    

    you get

    TC002:
    E203
    

    If you print the full message, you can see that the builtin messages do not have a colon. Of course, yesqa could strip the colon but I think that %(code)s should only return the code (without a colon). I did not dig deeper from this point. Maybe, it would be best to remove the colon? I'll attach a corresponding PR in a moment.

    opened by radoering 10
  • Fix #96 none handling for select and extend-select

    Fix #96 none handling for select and extend-select

    I'm not exactly sure if this is the best way to fix this issue, but this seems to be the only way to fix without haven't to rewrite a whole lot of tests.

    opened by wyuenho 8
  • Unexpected behavior regarding `attrs` support

    Unexpected behavior regarding `attrs` support

    I'm really sorry, but I think you may need to revert my changes regarding attrs support. It seems that attrs doesn't necessarily need runtime type annotiations and moving all out of TYPE_CHECKING block may result in circular imports.

    I will investigate how attrs handles runtime type annotations and come back with a fixed proposal.

    opened by sasanjac 8
  • Proposal to implement `attrs` support

    Proposal to implement `attrs` support

    • implemented a method that compiles imports in regard to attrs including their import alias
    • check at class definitions if any decorator is one of attrs dataclass decorators (matched against the actual import alias)
    opened by sasanjac 8
  • AttributeError from checker.py

    AttributeError from checker.py

    Hi,

    I just freshly installed this and flake8 on python3.7 and on any use I'm getting an error on simple flake8 file.py . Last call of the traceback is:

    File "c:\python37\lib\site-packages\flake8_type_checking\checker.py", line 325, in visit_FunctionDef for i in range(node.lineno, node.end_lineno + 1): # type: ignore AttributeError: 'FunctionDef' object has no attribute 'end_lineno'

    bug-report info: { "dependencies": [], "platform": { "python_implementation": "CPython", "python_version": "3.7.3", "system": "Windows" }, "plugins": [ { "is_local": false, "plugin": "flake8-type-checking", "version": "1.0.3" }, { "is_local": false, "plugin": "mccabe", "version": "0.6.1" }, { "is_local": false, "plugin": "pycodestyle", "version": "2.7.0" }, { "is_local": false, "plugin": "pyflakes", "version": "2.3.1" } ], "version": "3.9.2" }

    opened by Yobmod 8
  • feat: Support use of TYPE_CHECKING with simple boolean logic

    feat: Support use of TYPE_CHECKING with simple boolean logic

    For various reasons, modules may be conditioned on multiple criteria that determine whether they should be imported. For example, if we have an module that should be imported during testing or type checking, we may do something like:

    if TYPE_CHECKING or environment == 'test':
        import foobar
    

    Currently, the linter will flag the foobar import as needing to be moved into an if TYPE_CHECKING block in this scenario. This gives us two options, each of which is less than ideal. We could import the module twice, i.e.

    if TYPE_CHECKING:
        import foobar
    elif environment == 'test':
        import foobar
    

    or use a # noqa comment and lose the safety of the check when the code changes.

    This commit adds some logic to handle these types of simple conditionals and determine if they are equivalent to if TYPE_CHECKING: for the purposes of this linter. In our simple example, we should be able to determine that if TYPE_CHECKING or environment == 'test' will always result in the module being imported if TYPE_CHECKING is True. Similarly, we should be able to determine that if TYPE_CHECKING and environment == 'test' is not sufficient, since we have no guarantees about the value of environment.

    opened by steverice 7
  • Request: Support class attributes

    Request: Support class attributes

    Hi,

    So I got a pydantic model:

    from pydantic import BaseConfig, BaseModel
    
    from starlite.cache import CacheBackendProtocol
    from starlite.types import CacheKeyBuilder
    
    class CacheConfig(BaseModel):
        """Configuration for response caching.
    
        To enable response caching, pass an instance of this class to the
        [Starlite][starlite.app.Starlite] constructor using the
        'cache_config' key.
        """
    
        class Config(BaseConfig):
            arbitrary_types_allowed = True
    
        backend: CacheBackendProtocol
        expiration: int = 60 
        cache_key_builder: CacheKeyBuilder
    

    Both the backend and cache_key_builder attributes are typed using custom classes, which are imported only for typing purposes. Hence this would be possible:

    from typing import TYPE_CHECKING
    
    from pydantic import BaseConfig, BaseModel
    
    if TYPE_CHECKING:
        from starlite.cache import CacheBackendProtocol
        from starlite.types import CacheKeyBuilder
    
    class CacheConfig(BaseModel):
        """Configuration for response caching.
    
        To enable response caching, pass an instance of this class to the
        [Starlite][starlite.app.Starlite] constructor using the
        'cache_config' key.
        """
    
        class Config(BaseConfig):
            arbitrary_types_allowed = True
    
        backend: "CacheBackendProtocol"
        expiration: int = 60 
        cache_key_builder: "CacheKeyBuilder"
    

    I would like to ask for this feature to be included in this plugin.

    opened by Goldziher 7
  • Codes conflict with tryceraptops

    Codes conflict with tryceraptops

    Both flake8-type-checking and tryceraptops are using the same TC prefix in the same range, which makes it impossible to use both plugins at the same time. tryceraptops violations doc

    opened by Aplietexe 2
  • False negative TC100

    False negative TC100

    This example in https://github.com/snok/drf-openapi-tester isn't flagged with a TC100 when it should be. The Response annotation will otherwise lead to a runtime error.

    from typing import TYPE_CHECKING
    
    from django.urls import reverse
    from rest_framework.test import APITestCase
    
    from openapi_tester import SchemaTester
    from tests.utils import TEST_ROOT
    
    if TYPE_CHECKING:
        from rest_framework.response import Response
    
    schema_tester = SchemaTester(schema_file_path=str(TEST_ROOT) + "/schemas/sample-schemas/content_types.yaml")
    
    
    class BaseAPITestCase(APITestCase):
        """Base test class for api views including schema validation"""
    
        @staticmethod
        def assertResponse(response: Response, **kwargs) -> None:
            """helper to run validate_response and pass kwargs to it"""
            schema_tester.validate_response(response=response, **kwargs)
    
    
    class PetsAPITests(BaseAPITestCase):
        def test_get_pet_by_id(self):
            response = self.client.get(
                reverse(
                    "get-pet",
                    kwargs={
                        "petId": 1,
                    },
                ),
                content_type="application/vnd.api+json",
            )
            assert response.status_code == 200
            self.assertResponse(response)
    
    opened by sondrelg 0
  • TC004 reported for object that exists both inside and out of type checking block

    TC004 reported for object that exists both inside and out of type checking block

    See the following code: https://github.com/mesonbuild/meson/blob/d4733984e9e3970c23a9436dce8919f8a25194e8/mesonbuild/compilers/mixins/gnu.py#L30-L39

    if T.TYPE_CHECKING:
        from ...compilers.compilers import Compiler
    else:
        # This is a bit clever, for mypy we pretend that these mixins descend from
        # Compiler, so we get all of the methods and attributes defined for us, but
        # for runtime we make them descend from object (which all classes normally
        # do). This gives up DRYer type checking, with no runtime impact
        Compiler = object
    
    ...
    
    # this is a mixin
    class GnuLikeCompiler(Compiler, metaclass=abc.ABCMeta):
    

    This reports:

    mesonbuild/compilers/mixins/gnu.py:33:1: TC004 Move import 'Compiler' out of type-checking block. Import is used for more than type hinting.
    

    But weirdly enough, this type-checking only import is shadowed at runtime and thus not actually used. Not sure if there's a good way to detect it -- even the code comments imply it's a bit too clever.

    opened by eli-schwartz 4
  • Type-checking block errors not reported for imports used in `cast()` string annotation

    Type-checking block errors not reported for imports used in `cast()` string annotation

    Given the following code:

    from __future__ import annotations
    
    from collections.abc import Callable
    from typing import Any, cast
    
    from pendulum.datetime import DateTime
    
    from .foo import Foo
    
    a = cast('Callable[..., Any]', {})
    b = cast('DateTime', {})
    c = cast('Foo', {})
    

    And the following config:

    [flake8]
    select = TC,TC1
    

    No errors are reported at line 3 (TC003), line 6 (TC002), and line 8 (TC001).

    If the following function is added in the code, the errors are triggered:

    def asdf(a: Callable[..., Any], b: DateTime, c: Foo) -> None:
        ...
    
    bug 
    opened by bryanforbes 10
Releases(v2.3.0)
  • v2.3.0(Nov 20, 2022)

    New features

    • feat: Support use of TYPE_CHECKING with simple boolean logic by @steverice in https://github.com/snok/flake8-type-checking/pull/142

    Maintenance

    • Remove fix for "double namespace" imports by @steverice in https://github.com/snok/flake8-type-checking/pull/144
    • Add test coverage for stub file ignore by @steverice in https://github.com/snok/flake8-type-checking/pull/145

    New Contributors

    • @steverice made their first contribution in https://github.com/snok/flake8-type-checking/pull/144

    Full Changelog: https://github.com/snok/flake8-type-checking/compare/v2.2.0...v2.3.0

    Source code(tar.gz)
    Source code(zip)
  • v2.2.0(Oct 16, 2022)

    New features

    • feat: Add strict setting to opt-into v1 behavior by @sondrelg in https://github.com/snok/flake8-type-checking/pull/138

    Bugfixes

    • fix: Ignore TC100 for stub files by @sondrelg in https://github.com/snok/flake8-type-checking/pull/126
    • fix: Stop modifying node.attr by @sondrelg in https://github.com/snok/flake8-type-checking/pull/140

    Maintenance

    • chore: Update Poetry version to 1.2.0 by @sondrelg in https://github.com/snok/flake8-type-checking/pull/132
    • chore: remove upper bound from Python version specifier by @sisp in https://github.com/snok/flake8-type-checking/pull/134
    • docs: Expand and correct examples by @sondrelg in https://github.com/snok/flake8-type-checking/pull/135

    New Contributors

    • @sisp made their first contribution in https://github.com/snok/flake8-type-checking/pull/134

    Full Changelog: https://github.com/snok/flake8-type-checking/compare/v2.1.3...v2.2.0

    Source code(tar.gz)
    Source code(zip)
  • v2.1.3(Sep 1, 2022)

  • v2.1.2(Aug 4, 2022)

    Fixes

    • No longer flags TC001 (Move import into a type checking block) errors when imports are actually just completely unused. This error is already covered by F401.
    Source code(tar.gz)
    Source code(zip)
  • v2.1.1(Aug 4, 2022)

    Fixes

    • Correct TC101 (... does not need to be a string literal) logic so it only flags string literals (#122 by @shiftinv)
    • Fix a TC004 issue (Move import ... out of type-checking block) where we weren't handling all imports (#123 by @shiftinv)
    • Fix TC002 (Move import ... into type checking block) false positives (#124)
    Source code(tar.gz)
    Source code(zip)
  • v2.1.0(Jul 28, 2022)

    Adds a new error type, TC006, with error message Annotation in typing.cast() should be a string literal (#114, #118). Thanks @ngnpope 👏

    Source code(tar.gz)
    Source code(zip)
  • v2.0.7(Jul 27, 2022)

  • v2.0.6(Jul 14, 2022)

    Fixes

    • Remove packaging dependency. Implement tuple comparison to check flake8 semver major version.
    • Add flake8 call to test matrix, so we don't accidentally break the plugin in the same way again.
    Source code(tar.gz)
    Source code(zip)
  • v2.0.5(Jul 14, 2022)

    Fixes

    • Fix configuration issue preventing plugin from running flake8 v3
    • Fix false positive TC004 errors in new pipe-style (BinOr) annotations
    Source code(tar.gz)
    Source code(zip)
  • v2.0.4(Jul 13, 2022)

    Fixes

    • Rework plugin internals so it no longer impacts other plugins (#104, #95, #90)
    • Add missing support for Pydantic's validate_arguments decorator (#97)
    • Handle double-namespace imports (like from urllib.parse) properly (#103)
    • Add None handling for select and extend-select, so the plugin works with the current flake8 head (#98). Thanks @wyuenho 👍
    Source code(tar.gz)
    Source code(zip)
  • v2.0.3(Jul 9, 2022)

  • v2.0.2(Jul 5, 2022)

  • v2.0.1(Jun 20, 2022)

    Fixes

    • Removes deep copying of the received AST tree introduced in https://github.com/snok/flake8-type-checking/pull/81. No longer seems to be needed, and deep copying really large trees can lead to recursion errors.
    Source code(tar.gz)
    Source code(zip)
  • v2.0.0(Jun 20, 2022)

    Breaking changes

    • The plugin no longer returns errors when it finds an import that doesn't need to be evaluated at runtime, if there are already other runtime imports made to the same module. So if a third-party library already has 3 imports present in the file, we will no longer flag the 4th to be moved into a type checking block. See https://github.com/snok/flake8-type-checking/issues/84 for more context.

    • The old TC003 for discovery of multiple type-checking blocks was removed

    • TC002 used to flag third-party and built-in library imports. We have now split this into TC002 for third-party imports and. TC003 for built-in imports, using aspy.refactor-imports for the classification.

    None of these changes should produce new errors in existing projects.

    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(Apr 10, 2022)

    Features

    • Adds a type-checking-cattrs-enabled setting which prevents errors on class var annotations for attrs classes. Encapsulates the logic added in v1.4.0, since annotations on attrs classes don't actually need to be available at runtime, unless used with cattrs.
    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(Apr 3, 2022)

    Features

    • The plugin now automatically detects attrs classes. Type hints defined on attrs classes which need to be accessed at runtime should no longer be flagged (#78). Thanks @sasanjac for the contribution 👍
    Source code(tar.gz)
    Source code(zip)
  • v1.3.3(Mar 12, 2022)

    Fixes

    • Fix bug when combining plugin with flake8-bandit (stop reading private ast-node properties) (#74)
    • Make flake8-type-checking custom node property private (#74)
    Source code(tar.gz)
    Source code(zip)
  • v1.3.2(Feb 27, 2022)

    Fixes

    • Fixed TYPE_CHECKING block detection so it detects when conditions is made with typing.TYPE_CHECKING or using import aliases, not just TYPE_CHECKING (#73)
    Source code(tar.gz)
    Source code(zip)
  • v1.3.1(Jan 23, 2022)

    The release of v1.3.0 was a bit premature. It contained the wrong defaults for a few settings, so we yanked the release.

    These are the improvements and new features from v1.2.0:

    Features

    • Added FastAPI support (#60)

      Added a --type-checking-fastapi-enabled option to treat decorated function annotations as required at runtime. Note that FastAPI also evaluates the annotations of callables passed to Depends. That is not handled by this setting.

    • Added a FastAPI-dependency-support setting (#66)

      For users that wish to prevent false positives at all costs, this setting treats all function definitions as required at runtime. The setting is available using --type-checking-fastapi-dependency-support-enabled

    • Added support for opting into class var checking, when pydantic support is enabled (#67)

      When pydantic support is enabled, checking of type annotation for classes is completely disabled if the class has at least one base class. This setting allows users to specify specific base classes to check additionally. For example, typing classes like NamedTuple, TypedDict, and Protocol seem like good candidates. Can be used with --type-checking-pydantic-enabled-baseclass-passlist.

    Fixes and improvements

    • Corrected the flake8-extensions code in the project's pyproject.toml (was TCH rather than TC)
    • Removed dead changelog link in favour of releases link, in the pypi metadata
    • Removed pytest-cov in favour of just coverage
    • Rewrote sections of the docs
    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Jan 23, 2022)

    Features

    • Added FastAPI support (#60)

      Added a --type-checking-fastapi-enabled option to treat decorated function annotations as required at runtime. Note that FastAPI also evaluates the annotations of callables passed to Depends. For now that is not handled by the setting.

    Fixes and improvements

    • Corrected the flake8-extensions code in the project's pyproject.toml (was TCH rather than TC)
    • Removed dead changelog link in favour of releases link, in the pypi metadata
    • Removed pytest-cov in favour of just coverage
    • Rewrote sections of the docs
    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Jan 4, 2022)

    Features

    • Added Pydantic support (https://github.com/snok/flake8-type-checking/pull/58)

      For a quick summary of why Pydantic needs support in the first place: unlike most Python libraries, Pydantic evaluates annotations defined on their models at runtime. At the same time, this plugin is built on the assumption that imports which are only found in annotation slots, are not required at runtime. To make this work, we have added a --type-checking-pydantic-enabled option which, when toggled on, will treat all annotations from class variable annotations as required at runtime.

      This will lead to some false positives, e.g., for dataclass annotations, but in this case false positives are inconsequential and false negatives lead to runtime errors in prod, so better to favour the former in this case.

    Fixes

    • Fixed end_lineno inference for __all__ assignments (https://github.com/snok/flake8-type-checking/pull/59)
    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Jan 2, 2022)

  • v1.1.1(Nov 29, 2021)

  • v1.1.0(Nov 18, 2021)

  • v1.0.5(Nov 17, 2021)

  • v1.0.4(Oct 31, 2021)

    • Updates package metadata and dependencies, making it clear that the package will only work on Python 3.8 and above.
    • Adds handling for the ast.Index node type on Python 3.8, fixing some false negative TC101 errors
    Source code(tar.gz)
    Source code(zip)
  • v1.0.3(Jun 25, 2021)

  • v1.0.2(May 4, 2021)

  • v1.0.1(May 3, 2021)

  • v1.0.0(Apr 4, 2021)

Owner
snok
Open source collaboration
snok
Design by contract for Python. Write bug-free code. Add a few decorators, get static analysis and tests for free.

A Python library for design by contract (DbC) and checking values, exceptions, and side-effects. In a nutshell, deal empowers you to write bug-free co

Life4 473 Dec 28, 2022
Automated security testing using bandit and flake8.

flake8-bandit Automated security testing built right into your workflow! You already use flake8 to lint all your code for errors, ensure docstrings ar

Tyler Wince 96 Jan 01, 2023
Typed interface stubs for Pythonista iOS

Pythonista Stubs Stubs for the Pythonista iOS API. This allows for better error detection and IDE / editor autocomplete. Installation and Usage pip in

Harold Martin 12 Jul 14, 2020
MonkeyType as a pytest plugin.

MonkeyType as a pytest plugin.

Marius van Niekerk 36 Nov 24, 2022
Python classes with types validation at runtime.

typedclasses Python classes with types validation at runtime. (Experimental & Under Development) Installation You can install this library using Pytho

Izhar Ahmad 8 Feb 06, 2022
🦆 Better duck-typing with mypy-compatible extensions to Protocol

🦆 Quacks If it walks like a duck and it quacks like a duck, then it must be a duck Thanks to PEP544, Python now has protocols: a way to define duck t

Arie Bovenberg 9 Nov 14, 2022
Optional static typing for Python 3 and 2 (PEP 484)

Mypy: Optional Static Typing for Python Got a question? Join us on Gitter! We don't have a mailing list; but we are always happy to answer questions o

Python 14.4k Jan 08, 2023
Check for python builtins being used as variables or parameters

Flake8 Builtins plugin Check for python builtins being used as variables or parameters. Imagine some code like this: def max_values(list, list2):

Gil Forcada Codinachs 98 Jan 08, 2023
Flake8 plugin to find commented out or dead code

flake8-eradicate flake8 plugin to find commented out (or so called "dead") code. This is quite important for the project in a long run. Based on eradi

wemake.services 277 Dec 27, 2022
Easy saving and switching between multiple KDE configurations.

Konfsave Konfsave is a config manager. That is, it allows you to save, back up, and easily switch between different (per-user) system configurations.

42 Sep 25, 2022
docstring style checker

pydocstyle - docstring style checker pydocstyle is a static analysis tool for checking compliance with Python docstring conventions. pydocstyle suppor

Python Code Quality Authority 982 Jan 03, 2023
Tools for improving Python imports

imptools Tools for improving Python imports. Installation pip3 install imptools Overview Detailed docs import_path Import a module from any path on th

Danijar Hafner 7 Aug 07, 2022
Unbearably fast O(1) runtime type-checking in pure Python.

Look for the bare necessities, the simple bare necessities. Forget about your worries and your strife. — The Jungle Book.

beartype 1.4k Jan 01, 2023
Code audit tool for python.

Pylama Code audit tool for Python and JavaScript. Pylama wraps these tools: pycodestyle (formerly pep8) © 2012-2013, Florent Xicluna; pydocstyle (form

Kirill Klenov 967 Jan 07, 2023
Flake8 wrapper to make it nice, legacy-friendly, configurable.

THE PROJECT IS ARCHIVED Forks: https://github.com/orsinium/forks It's a Flake8 wrapper to make it cool. Lint md, rst, ipynb, and more. Shareable and r

Life4 232 Dec 16, 2022
Mypy plugin and stubs for SQLAlchemy

Pythonista Stubs Stubs for the Pythonista iOS API. This allows for better error detection and IDE / editor autocomplete. Installation and Usage pip in

Dropbox 521 Dec 29, 2022
An extension for flake8 that forbids some imports statements in some modules.

flake8-obey-import-goat An extension for flake8 that forbids some imports statements in some modules. Important: this project is developed using DDD,

Ilya Lebedev 10 Nov 09, 2022
Mypy stubs, i.e., type information, for numpy, pandas and matplotlib

Mypy type stubs for NumPy, pandas, and Matplotlib This is a PEP-561-compliant stub-only package which provides type information for matplotlib, numpy

Predictive Analytics Lab 194 Dec 19, 2022
Flake8 plugin for managing type-checking imports & forward references

flake8-type-checking Lets you know which imports to put in type-checking blocks. For the imports you've already defined inside type-checking blocks, i

snok 67 Dec 16, 2022
A simple plugin that allows running mypy from PyCharm and navigate between errors

mypy-PyCharm-plugin The plugin provides a simple terminal to run fast mypy daemon from PyCharm with a single click or hotkey and easily navigate throu

Dropbox 301 Dec 09, 2022