Flake8 Type Annotation Checking

Overview

flake8-annotations

PyPI - Python Version PyPI PyPI - License pre-commit.ci status Code style: black Open in Visual Studio Code

flake8-annotations is a plugin for Flake8 that detects the absence of PEP 3107-style function annotations and PEP 484-style type comments (see: Caveats).

What this won't do: Check variable annotations (see: PEP 526), respect stub files, or replace mypy.

Installation

Install from PyPi with your favorite pip invocation:

$ pip install flake8-annotations

It will then be run automatically as part of flake8.

You can verify it's being picked up by invoking the following in your shell:

$ flake8 --version
4.0.0 (flake8-annotations: 2.7.0, mccabe: 0.6.1, pycodestyle: 2.8.0, pyflakes: 2.4.0) CPython 3.10.0 on Darwin

Table of Warnings

All warnings are enabled by default.

Function Annotations

ID Description
ANN001 Missing type annotation for function argument
ANN002 Missing type annotation for *args
ANN003 Missing type annotation for **kwargs

Method Annotations

ID Description
ANN101 Missing type annotation for self in method1
ANN102 Missing type annotation for cls in classmethod1

Return Annotations

ID Description
ANN201 Missing return type annotation for public function
ANN202 Missing return type annotation for protected function
ANN203 Missing return type annotation for secret function
ANN204 Missing return type annotation for special method
ANN205 Missing return type annotation for staticmethod
ANN206 Missing return type annotation for classmethod

Type Comments

ID Description
ANN301 PEP 484 disallows both type annotations and type comments

Notes:

  1. See: PEP 484 and PEP 563 for suggestions on annotating self and cls arguments.

Configuration Options

Some opinionated flags are provided to tailor the linting errors emitted.

--suppress-none-returning: bool

Suppress ANN200-level errors for functions that meet one of the following criteria:

  • Contain no return statement, or
  • Explicit return statement(s) all return None (explicitly or implicitly).

Default: False

--suppress-dummy-args: bool

Suppress ANN000-level errors for dummy arguments, defined as _.

Default: False

--allow-untyped-defs: bool

Suppress all errors for dynamically typed functions. A function is considered dynamically typed if it does not contain any type hints.

Default: False

--allow-untyped-nested: bool

Suppress all errors for dynamically typed nested functions. A function is considered dynamically typed if it does not contain any type hints.

Default: False

--mypy-init-return: bool

Allow omission of a return type hint for __init__ if at least one argument is annotated. See mypy's documentation for additional details.

Default: False

--dispatch-decorators: list[str]

Comma-separated list of decorators flake8-annotations should consider as dispatch decorators. Linting errors are suppressed for functions decorated with at least one of these functions.

Decorators are matched based on their attribute name. For example, "singledispatch" will match any of the following:

  • import functools; @functools.singledispatch
  • import functools as fnctls; @fnctls.singledispatch
  • from functools import singledispatch; @singledispatch

NOTE: Deeper imports, such as a.b.singledispatch are not supported.

See: Generic Functions for additional information.

Default: "singledispatch, singledispatchmethod"

--overload-decorators: list[str]

Comma-separated list of decorators flake8-annotations should consider as typing.overload decorators.

Decorators are matched based on their attribute name. For example, "overload" will match any of the following:

  • import typing; @typing.overload
  • import typing as t; @t.overload
  • from typing import overload; @overload

NOTE: Deeper imports, such as a.b.overload are not supported.

See: The typing.overload Decorator for additional information.

Default: "overload"

Generic Functions

Per the Python Glossary, a generic function is defined as:

A function composed of multiple functions implementing the same operation for different types. Which implementation should be used during a call is determined by the dispatch algorithm.

In the standard library we have some examples of decorators for implementing these generic functions: functools.singledispatch and functools.singledispatchmethod. In the spirit of the purpose of these decorators, errors for missing annotations for functions decorated with at least one of these are ignored.

For example, this code:

import functools

@functools.singledispatch
def foo(a):
    print(a)

@foo.register
def _(a: list) -> None:
    for idx, thing in enumerate(a):
        print(idx, thing)

Will not raise any linting errors for foo.

Decorator(s) to treat as defining generic functions may be specified by the --dispatch-decorators configuration option.

The typing.overload Decorator

Per the typing documentation:

The @overload decorator allows describing functions and methods that support multiple different combinations of argument types. A series of @overload-decorated definitions must be followed by exactly one non-@overload-decorated definition (for the same function/method).

In the spirit of the purpose of this decorator, errors for missing annotations for non-@overload-decorated functions are ignored if they meet this criteria.

For example, this code:

import typing


@typing.overload
def foo(a: int) -> int:
    ...

def foo(a):
    ...

Will not raise linting errors for missing annotations for the arguments & return of the non-decorated foo definition.

Decorator(s) to treat as typing.overload may be specified by the --overload-decorators configuration option.

Caveats for PEP 484-style Type Comments

Mixing argument-level and function-level type comments

Support is provided for mixing argument-level and function-level type comments.

def foo(
    arg1,  # type: bool
    arg2,  # type: bool
):  # type: (...) -> bool
    pass

Note: If present, function-level type comments will override any argument-level type comments.

Partial type comments

Partially type hinted functions are supported for non-static class methods.

For example:

class Foo:
    def __init__(self):
        # type: () -> None
        ...

    def bar(self, a):
        # type: (int) -> int
        ...

Will consider bar's self argument as unannotated and use the int type hint for a.

Partial type comments utilizing ellipses as placeholders is also supported:

def foo(arg1, arg2):
    # type: (bool) -> bool
    pass

Will show arg2 as missing a type hint.

def foo(arg1, arg2):
    # type: (..., bool) -> bool
    pass

Will show arg1 as missing a type hint.

Deprecation notice: Explicit support for utilization of ellipses as placeholders will be removed in version 3.0. See this issue for more information.

Contributing

Development Environment

This project uses Poetry to manage dependencies. With your fork cloned to your local machine, you can install the project and its dependencies to create a development environment using:

$ poetry install

Note: An editable installation of flake8-annotations in the developer environment is required in order for the plugin to be registered for Flake8. By default, Poetry includes an editable install of the project itself when poetry install is invoked.

A pre-commit configuration is also provided to create a pre-commit hook so linting errors aren't committed:

$ pre-commit install

Testing & Coverage

A pytest suite is provided, with coverage reporting from pytest-cov. A tox configuration is provided to test across all supported versions of Python. Testing will be skipped for Python versions that cannot be found.

$ tox

Details on missing coverage, including in the test suite, is provided in the report to allow the user to generate additional tests for full coverage.

Comments
  • Add Flag to Suppress Warnings for Dynamically Typed Functions

    Add Flag to Suppress Warnings for Dynamically Typed Functions

    For consistency with mypy, it would be nice to have an option/rule that behaved the same way as mypy regarding typing of __init__().

    Currently, flake8-annotations always raises a violation if there is no return type annotation.

    Mypy, however, raises an error if there are no annotations at all (as this would indicate an untyped function). i.e. If there are any annotations on parameters, then a return type is not needed. The return type is only needed when there are no parameters in order to mark the function as statically typed. e.g. def __init__(self, foo: str): and def __init__(self) -> None: are both correctly typed.

    enhancement 
    opened by Dreamsorcerer 12
  • [Meta] Versioning Scheme

    [Meta] Versioning Scheme

    What versioning scheme would make sense for this package?

    I'm debating between the following two options:

    I'm leaning towards CalVer. Because this is a utility plugin to flake8 with nothing externally facing or backwards incompatible (flake8 compatibility is handled by version pinning), I'm finding it hard to come up with a meaningful metric to use for incrementing major/minor versions of the package; major, in particular.

    One caveat to this would be the addition of error codes that would require the user to adjust their ignore settings, but I think this would be an issue with SemVer as well. This seems pretty simply solved by suffixing the error codes table in the README with something like "introduced in ..."

    question 
    opened by sco1 8
  • ANN201 false positive when functions are defined within functions

    ANN201 false positive when functions are defined within functions

    Describe the bug When an outer function returns None, but a function which is defined within it returns something that isn't None, the outer function is falsly marked with an ANN2** error.

    Edit: Note this happens even when suppress-none-returning = True.

    To Reproduce Minimal code example to reproduce the behavior:

    def foo():
        def bar() -> int:
            return 1
    
        print(bar())
    
    
    foo()
    

    When running with --supress-none-returning:

    $ flake8 --suppress-none-returning test.py
    test.py:1:11: ANN201 Missing return type annotation for public function
    

    Version Information

    $ flake8 --version
    3.7.9 (flake8-annotations: 2.0.0, flake8-comprehensions: 3.2.2, flake8-print: 3.1.4, flake8_pep3101: 1.2.1, import-order: 0.18.1, mccabe: 0.6.1, pycodestyle: 2.5.0, pyflakes: 2.1.1) CPython 3.8.1 on Linux
    

    As well as your Python version:

    $ python -V
    Python 3.8.1
    
    bug 
    opened by sumnerevans 5
  • Support type comments (PEP 484)

    Support type comments (PEP 484)

    Add the ability to process type comments in addition to annotations, per PEP 484. Example:

    def some_func(arg1, arg2, arg3=True):
        # type: (Optional[str], int, bool) -> Optional[str]
        ...
    

    Rationale/use cases

    • Improves "out of the box" support and encourages migration for projects moving from Python 2 to Python 3
    • Projects that don't have annotations for other reasons (compatibility, DSLs, performance)
    • Extension modules
    • Modules that use annotations for other purposes

    Note: mypy supports type comments, so it may have some parsing code that could be adapted.

    enhancement 
    opened by GhostofGoes 5
  • Testing!

    Testing!

    This PR adds testing, yay! This is my first foray into formal testing with Python so please help me be sure I'm not doing something completely terrible.

    Here are the currently targeted points for testing:

    • [x] Function parsing
    • [x] Argument parsing
    • [x] Classification of Function as fully annotated
    • [x] Warning classification
    • [x] Emitting correct line & column numbers
    • [x] Formatting warning message with argument name (where relevant)
    • [x] Outputting correct tuple for flake8
    • [x] Function and Argument object __str__ and __repr__ methods

    Additionally:

    • Adds testing to the CI & a blurb in the README
    • Adds coverage reporting as a pipenv script.
    • Adds coverage reporting to CI
    • Replaces the debug string methods for Annotation and Function with proper __str__ and __repr__ methods
    • Adds a Dependabot configuration file to limit the scope of the dependency checking to the non-dev dependences. I have enabled Dependabot for this project in order to help with keeping on top of changes to flake8.
    • Fixes incorrectly configured flake8-docstrings (see: https://github.com/python-discord/organisation/issues/131)

    See: #7 Closes: #16 Closes: #17 Closes: #19

    opened by sco1 5
  • Add handling for @property decorator

    Add handling for @property decorator

    The @property decorator was overlooked when creating the initial parsing logic.

    Support for this should be added:

    • [x] ClassDecoratorType enum constant
      • For the purposes of this tool, property, getter, setter, and deleter can probably safely be combined into a single PROPERTY constant
    • [x] Handling by AST parser
    • [x] Add error codes
    • [x] Add error classification
    enhancement 
    opened by sco1 5
  • 400 level errors on by default

    400 level errors on by default

    Describe the bug

    We just upgraded to 2.8.0 and have a bunch of litning errors stemming from code using the Any annotation. It looks like from the docs that those errors are intended to be off by default, but it's unclear from the docs how one would turn them on, and so I can't figure out if there's something we've done to turn them on, or if they're just actually on by default.

    Is this a bug, or do we need to just disable this error?

    Version Information Please provide the full output of flake8 --version

    $ flake8 --version
    4.0.0 (flake8-annotations: 2.8.0, flake8-bandit: 3.0.0, flake8-docstrings:
    1.6.0, pydocstyle: 6.1.1, flake8_isort: 4.1.1, mccabe: 0.6.1, pycodestyle:
    2.8.0, pyflakes: 2.4.0) CPython 3.7.12 on Linux
    

    As well as your Python version:

    $ python -V
    Python 3.7.12
    
    
    opened by agbaum 4
  • Check that collection generics are parametrised

    Check that collection generics are parametrised

    Description

    Introduce warnings checking that collection generics are parametrised (even just by typing.Any).

    I'm happy to work on it, but I would like to first hear feedback if this check makes sense, if yes what generics should be covered, should it be disabled by default for backwards compatibility and lastly – what are some good commits that I can follow to see how to implement it.

    Rationale/Use Case

    I often see people annotate their code with really unhelpful types such as list, typing.List, dict or typing.Dict purely to satisfy flake8-annotations warnings.

    The idea is to nudge the developer into considering how their generic will be parametrised.

    I.e. this would fail:

    def my_fun(data: dict) -> None:
      return
    

    But that would be fine:

    from typing import Any
    
    def my_fun(data: dict[Any, Any]) -> None:
      return
    

    Of course, the idea is that this would make the developer consider declaring the type parameters even more precisely, e.g.:

    from typing import Any
    
    def my_fun(data: dict[str, Any]) -> None:
      return
    

    Or even:

    def my_fun(data: dict[str, int]) -> None:
      return
    

    CC: @flaviojdz – we spoke about it a few months ago!

    opened by kkom 4
  • Document expected or recommended annotations to avoid ANN101 and ANN102 errors

    Document expected or recommended annotations to avoid ANN101 and ANN102 errors

    Description Currently flake8-annotations will report an error if the self or cls parameters are not annotated. It is not clear what flake8-annotations wants from the source code in order not to report these errors, and neither PEP 484 nor PEP 3107 offers any guidance as to how self or cls should be annotated. In fact PEP 484 suggests in Annotating class and instance methods that such annotation is not generally necessary:

    In most cases the first argument of class and instance methods does not need to be annotated, and it is assumed to have the type of the containing class for instance methods, and a type object type corresponding to the containing class object for class methods.

    This means that the out-of-the-box behaviour of flake8-annotations appears (at least at first glance) contrary to the guidelines of the PEPs it is supposed to be enforcing.

    Given that neither PEP 484 nor PEP 3107 offer any general guidance on annotating self or cls parameters, the flake8-annotations README should add some examples of how to handle/avoid these errors.

    Rationale/Use Case

    Behaviour observed with flake8==3.7.9, flake8-annotations==2.0.1, running on CPython 3.7.6.

    The error can be seen with even a very trivial class, e.g.:

    class Foo:
        def __call__(self) -> float:
            return 1.0
    

    I'm assuming here that the answer is not something like:

    class Foo:
        def __call__(self: "Foo") -> float:
            return 1.0
    

    which works, but is rather boilerplate-y and would make renaming a class very annoying.

    I'm also assuming that the answer is not just "suppress that class of errors", e.g. with

    flake8 --extend-ignore=ANN101,ANN102
    

    which would seem a bit excessive given that there are probably a subset of cases (e.g. those mentioned in the PEP 484 link above) where one probably does want a self or cls annotation. (If it's possible to suppress ANN101 and 102 and still get validation of those special cases, it would be good to have a clear indication of that.)

    Basically, please offer some clear guidance on this, given that the PEPs referred to would suggest that un-annotated self and cls is just fine most of the time, and hence flake8-annotations out-of-the-box behaviour is quite unintuitive.

    opened by joseph-wakeling-frequenz 4
  • Migrate from Pipenv to Poetry

    Migrate from Pipenv to Poetry

    I'd like to propose for discussion migrating the management of the developer environment from Pipenv to Poetry.

    I've created a branch with a complete migration of the project for investigation here: https://github.com/python-discord/flake8-annotations/tree/poetry-adventures

    I will state up front that there is no major advantage to making this switch, but rather a collection of minor differences that contribute to what I believe is an overall improvement for the developer. In the fairly recent past PyDis looked into migrating all of the repositories to Poetry, as at the time there was a mix between Pipenv and Poetry utilization. It was decided to unify on Pipenv, as it provides some functionality that's very useful for local development, like pipenv run scripts and support for local .env files when executing these scripts. It also provides the useful check for an up-to-date lock file during deployment for the build to proceed. Poetry's advantages related to building & uploading to PyPI are not useful for most of our repositories since they do not live on PyPI.

    Pipenv's deployment-specific advantages

    As flake8-annotations is a library, Pipenv's deployment-specific advantages & .env file support are not relevant here.

    Poetry's lack of a pipenv run script equivalent

    While Poetry does have a poetry run command, it lacks Pipenv's capability for defining scripts in the project configuration and instead is limited to executing the project via defined entry points. While a disadvantage for some of our other repositories that utilize some fairly detailed scripts to reduce developmoent tasks to one-liners, development of flake8-annotations has no need for this enhanced functionality. Both linting (poetry run flake8) and testing (tox) are similarly simply accomplished. poetry run flake8 is also insertable into the pre-commit config, preventing us from having to sync linting dependencies in the config file; we're currently using pipenv run lint to accomplish the same.

    Simplification of dependency definition

    Currently, project dependencies need to be synced between the Pipfile and setup.py. While we have a CI tool to check for synchronization (pipenv-check), which helps, it only checks for version conflicts and not absolute synchronization. Migrating to Poetry allows us to utilize a singular pyproject.toml file for dependency specifications. As it is a Python standard (ish?) format, it's supported by pip for installation without requiring Poetry as well. As the support landscape expands, things like tox and flake8 would also be able to be migrated into the file as well (tox currently has support but it's as a giant string, which I feel is less readable). This is a pretty significant quality of life advantage over Pipenv.

    I have plans to declare black as an explicit dev dependency (it's already run locally), which requires pyproject.toml anyway.

    Poetry's build tools

    Poetry also provides built-in build tools, allowing for distributions to be built via the poetry built one-liner. While the python setup.py sdist bdist_wheel isn't super challenging, and is run by CI only anyway, it's still a nice simplifying one-liner to have.

    Pipenv's future?

    With pipenv's transfer of ownership to PyPA, development publically seems to have stalled. While the developers have fairly recently stated that work is progressing & blocked by a myriad of issues, communication has been scarce. Poetry, on the other hand, has a very active development cycle, with a recent 1.0 release & impending addition of a plugin API to support OSS contributions of functionality that is lacking from the core tool.

    opened by sco1 4
  • Inadequate pre-commit linting configuration

    Inadequate pre-commit linting configuration

    This repository’s flake8 pre-commit configuration currently utilizes the latest PyPi version of flake8-annotations when building its linting environment rather than the current state of the local repo. This can potentially lead to a result that conflicts with both a manual flake8 invocation and the linting CI pipeline, which utilize the current state of the repo to lint itself.

    My research into method(s) to resolve this hasn’t been fruitful. Perhaps linting ourselves is an antipattern or I’m just bad at finding things on the internet, but if there’s no way to solve this then I’m inclined to remove pre-commit completely rather than have this conflict.

    Would love to have some opinions and/or leads on this!

    help wanted 
    opened by sco1 4
  • Add ANN300-level Error for Mixed Ellipses and Type Comments

    Add ANN300-level Error for Mixed Ellipses and Type Comments

    As touched on in #92, the current definition of and support for ellipses in partial type comments clashes with guidance provided in PEP 484:

    Sometimes you want to specify the return type for a function or method without (yet) specifying the argument types. To support this explicitly, the argument list may be replaced with an ellipsis. Example:

    def send_email(address, sender, cc, bcc, subject, body):
        # type: (...) -> bool
        """Send an email message.  Return True if successful."""
        <code>
    

    This plugin currently supports mixing of ellipses and types within the same type comment as a means for partial hinting. For example, from the README:

    def foo(arg1, arg2):
        # type: (..., bool) -> bool
        pass
    

    Will show arg1 as missing a type hint.

    While technically valid code, this type of notation is ambiguous and causes tools like mypy to error:

    error: Ellipses cannot accompany other argument types in function type signature
    

    This issue proposes the addition of an ANN300-level error to lint for this mixing of ellipses, as well as dropping explicit support for these annotations within the framework. This is considered a breaking change and will therefore be included in a major release. The new error may be introduced in a point release for compatibility evaluation, but will remain off by default until a major release.

    enhancement deferred 
    opened by sco1 1
Releases(v2.9.1)
  • v2.9.1(Aug 1, 2022)

    [v2.9.1]

    Changed

    • #144 Unpin the version ceiling for attrs.

    Fixed

    • Fix unit tests for opinionated warning codes in flake8 >= 5.0 (See: https://github.com/pycqa/flake8/issues/284)
    Source code(tar.gz)
    Source code(zip)
  • v2.9.0(Apr 15, 2022)

  • v2.8.0(Mar 30, 2022)

    [v2.8.0]

    Added

    • #131 Add the ANN4xx error level for opinionated warnings that are disabled by default.
    • #131 Add ANN401 for use of typing.Any as an argument annotation.

    Changed

    • Python 3.7 is now the minimum supported version
    Source code(tar.gz)
    Source code(zip)
  • v2.7.0(Oct 11, 2021)

  • v2.6.2(Apr 1, 2021)

  • v2.6.1(Mar 16, 2021)

  • v2.6.0(Mar 5, 2021)

    Changelog

    [v2.6.0]

    Added

    • #98 Add --dispatch-decorators to support suppression of all errors from functions decorated by decorators such as functools.singledispatch and functools.singledispatchmethod.
    • #99 Add --overload-decorators to support generic aliasing of the typing.overload decorator.

    Fixed

    • #106 Fix incorrect parsing of multiline docstrings with less than two lines of content, causing incorrect line numbers for yielded errors in Python versions prior to 3.8

    Additional Details

    Generic Functions

    Per #98, the functools.singledispatch and functools.singledispatchmethod decorators transform a function into a single-dispatch generic function.

    For example:

    import functools
    
    @functools.singledispatch
    def foo(a):
        print(a)
    
    @foo.register
    def _(a: list) -> None:
        for idx, thing in enumerate(a):
            print(idx, thing)
    

    Is correctly annotated but would previously yield linting errors for foo. In the spirit of the purpose of these decorators, linting errors are now suppressed for functions decorated with these decorators. The --dispatch-decorators configuration option has been added, which specifies a comma-separated list of decorators to be considered as dispatch decorators.

    Decorators are matched based on their attribute name. For example, "singledispatch" will match any of the following:

    • import functools; @functools.singledispatch
    • import functools as fnctls; @fnctls.singledispatch
    • from functools import singledispatch; @singledispatch

    By default, linting errors are suppressed for functions decorated by singledispatch or singledispatchmethod.

    typing.overload decorator aliasing

    Per #99, handling of the typing.overload has been made generic, removing the caveat from the initial implementation. The --overload-decorators configuration option has been added, which specifies a comma-separated list of decorators to be considered as typing.overload decorators.

    Decorators are now matched based on their attribute name. For example, "overload" will match any of the following:

    • import typing; @typing.overload
    • import typing as t; @t.overload
    • from typing import overload; @overload

    By default, linting errors are suppressed for functions decorated by overload, which should be a transparent change from v2.4 (#97).

    Source code(tar.gz)
    Source code(zip)
    flake8-annotations-2.6.0.tar.gz(20.29 KB)
    flake8_annotations-2.6.0-py3-none-any.whl(19.33 KB)
  • v2.5.0(Jan 4, 2021)

    Changelog

    [v2.5.0]

    Added

    • #103 add --allow-untyped-nested to suppress all errors from dynamically typted nested functions. A function is considered dynamically typed if it does not contain any type hints.

    Additional Details

    Per #102, nested functions can fall into an interesting spot semantically for a project. They're distinct enough from private/secret functions that one may not want to strictly enforce annotation (e.g. decorator definitions) but there does not exist a mechanism to do so without either noqa or just allowing all dynamically typed functions (via --allow-untyped-defs). The --allow-untyped-nested flag allows for this stricter subset of dynamic functions.

    Source code(tar.gz)
    Source code(zip)
    flake8-annotations-2.5.0.tar.gz(17.10 KB)
    flake8_annotations-2.5.0-py3-none-any.whl(18.35 KB)
  • 2.4.1(Sep 29, 2020)

  • v2.4.0(Sep 9, 2020)

    [v2.4.0]

    Fixed

    • #92 Fix inconsistent linting behavior between function-level type comments and their equivalent PEP 3107-style function annotations of class methods and classmethods.
    • #94 Fix improper handling of the closing definition in a series of typing.overload decorated functions.

    Additional Details

    Function-level type comment changes

    Per #92, there exists a discrepancy in behavior between linting of functions with PEP 3107-style annotations and PEP 484-style function-level type comments. Because PEP 484 does not describe a method to provide partial function-level type comments, there is a potential for ambiguity in the context of both class methods and classmethods when aligning type comments to method arguments.

    These two class methods, for example, should lint equivalently:

        def bar(self, a):
            # type: (int) -> int
            ...
    
        def bar(self, a: int) -> int
            ...
    

    When this example type comment is parsed by ast and then matched with the method's arguments, it associates the int hint to self rather than a, so a dummy hint needs to be provided in situations where self or class are not hinted in the type comment in order to achieve equivalent linting results to PEP-3107 style annotations.

    A dummy ast.Ellipses constant is injected into the parsed node if the following criteria are met:

    1. The function node is either a class method or classmethod
    2. The number of hinted args is at least 1 less than the number of function args

    typing.overload decorator handling

    Per #94, the typing.overload was being handled too literally (aka: ignored) by the linter, resulting in emitted linting errors that do not align with the purpose of the decorator.

    For example, this code:

    import typing
    
    
    @typing.overload
    def foo(a: int) -> int:
        ...
    
    def foo(a):
        ...
    

    Would raise linting errors for missing annotations for the arguments & return of the non-decorated foo definition; this interpretation disagrees with the purpose of the decorator.

    Per the documentation:

    A series of @overload-decorated definitions must be followed by exactly one non-@overload-decorated definition (for the same function/method)

    Errors for missing annotations for non-@overload-decorated functions are now ignored if they meet this criteria.

    NOTE: If importing directly, the typing.overload decorator will not be recognized if it is imported with an alias (e.g. from typing import overload as please_dont_do_this). Aliasing of the typing module is supported (e.g. import typing as t; @t.overload)

    Source code(tar.gz)
    Source code(zip)
  • v2.3.0(Jul 12, 2020)

    [v2.3.0]

    Added

    • #87 Add --mypy-init-return to allow omission of a return type hint for __init__ if at least one argument is annotated.

    Additional Details

    To help provide compatibility with Mypy for maintainers that wish to do so, the --mypy-init-return flag has been introduced to mimic Mypy's allowance for the omission of return type hints for __init__ methods that are not dynamically typed (at least one argument is annotated). With this flag set, ANN200 level errors will be suppressed for __init__ methods if at least one argument is explicitly annotated.

    For example, from Mypy's documentation:

    class C1:  # Return annotated
        def __init__(self) -> None:
            self.var = 42
    
    class C2:  # Return annotated
        def __init__(self, arg: int):
            self.var = arg
    
    class C3:
        def __init__(self):  # Return not annotated
            # This body is not type checked
            self.var = 42 + 'abc'
    

    NOTE: By default, Mypy does not enforce annotations for self in class methods, so to completely mimic Mypy's behavior with flake8-annotations ANN101 will need to be added to the repository's ignored linting codes.

    See Mypy's documentation for additional details: https://mypy.readthedocs.io/en/stable/class_basics.html?#annotating-init-methods

    Source code(tar.gz)
    Source code(zip)
    flake8-annotations-2.3.0.tar.gz(16.12 KB)
    flake8_annotations-2.3.0-py3-none-any.whl(16.14 KB)
  • v2.2.1(Jul 10, 2020)

  • v2.2.0(Jul 6, 2020)

    [v2.2.0]

    Added

    • #87 Add --allow-untyped-defs to suppress all errors from dynamically typed functions. A function is considered dynamically typed if it does not contain any type hints.

    Fixed

    • #77, #81 Fix incorrect return error locations in the presence of a multiline docstring containing colon(s)
    • #81 Fix incorrect return error locations for single-line function definitions
    • Fix incorrectly pinned project specifications
    Source code(tar.gz)
    Source code(zip)
    flake8-annotations-2.2.0.tar.gz(15.68 KB)
    flake8_annotations-2.2.0-py3-none-any.whl(15.67 KB)
  • v2.1.0(Apr 11, 2020)

  • v2.0.1(Mar 1, 2020)

    v2.0.1

    Added

    • #71 Add pep8-naming to linting toolchain
    • Expand pre-commit hooks
      • Add black
      • Add check-merge-conflict
      • Add check-toml
      • Add check-yaml
      • Add end-of-file-fixer
      • Add mixed-line-ending
      • Add python-check-blanket-noqa

    Changed

    • Add argument names to Argument and Function __repr__ methods to make the string more helpful to read

    Fixed

    • #70 Fix incorrect column index for missing return annotations when other annotations are present on the same line of source
    • #69 Fix misclassification of None returning functions when they contained nested functions with non-None returns (thanks @isidentical!)
    • #67 Fix methods of nested classes being improperly classified as "regular" functions (thanks @isidentical!)

    Additional Details

    The previous approach being taken for nesting as to use a generic_visit() on the node to visit any nested functions. However, from the bugs reported (#67, #69) it was made clear that this approach was too generic & a method for either restricting or keeping track of the depth of this generic visit was required.

    Both the FunctionVisitor and ReturnVisitor classes have been rearchitected to keep track of the parent context of the nodes being visited in order to properly classify methods of nested classes and return values of nested functions, respectively.

    You can view a full writeup here on discuss.python.org.

    Source code(tar.gz)
    Source code(zip)
    flake8-annotations-2.0.1.tar.gz(14.57 KB)
    flake8_annotations-2.0.1-py3-none-any.whl(14.57 KB)
  • v2.0.0(Feb 11, 2020)

    [v2.0.0]

    Changed

    • #64 Change prefix from TYP to ANN in order to deconflict with flake8-typing-imports

    Additional Details

    Per #64, due to prefix shadowing of TYP between flake8-annotations and flake8-typing-imports, it's been suggested that the prefix for this repository be changed to ANN so the plugins can coexist peacefully.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Feb 10, 2020)

    [v1.2.0]

    Added

    • Add test case for checking whether flake8 invokes our plugin
    • #41 Add --suppress-none-returning configuration option to suppress TYP200 level errors for functions that either lack a return statement or only explicitly return None.
    • Add black as an explicit developer requirement (codebase already adheres to black formatting)

    Changed

    • #61 Migrate from Pipenv to Poetry for developer environment setup

    Additional Details:

    This release adds the --suppress-none-returning configuration option, as requested by #41. If this flag is set, TYP200-level errors are suppressed for functions that meet one of the following criteria:

    • Contain no return statement, or
    • Explicit return statement(s) all return None (explicitly or implicitly).

    For example:

    def foo():
        """This is a test function."""
        a = 2 + 2
        if a == 4:
            return None
        else:
            return
    

    Will not yield a TYP201 error, with the flag set:

    $ flake8 test.py
    test.py:1:11: TYP201 Missing return type annotation for public function
    $ flake8 test.py --suppress-none-returning
    <No output>
    

    And:

    def foo():
        """This is a test function."""
        a = 2 + 2
        if a == 4:
            return True
        else:
            return
    

    Will still yield a TYP201 error, with the flag set:

    $ flake8 test.py
    test.py:1:11: TYP201 Missing return type annotation for public function
    $ flake8 test.py --suppress-none-returning
    test.py:1:11: TYP201 Missing return type annotation for public function
    

    The default value of this configuration option is False, so this addition should be transparent to existing users.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.3(Dec 20, 2019)

    [v1.1.3]

    Fixed

    • Add missing classifier test cases for POSONLYARGS
    • Re-add the tree argument to the checker so flake8 identifies the plugin as needing to run
    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Dec 17, 2019)

    [v1.1.2]

    Changed

    • Request source from flake8 as lines of code rather than parsing it from the requested filename ourselves, allowing for proper parsing of stdin inputs
    • Remove flake8-string-format from dev dependencies, as str.format() isn't used anywhere

    Fixed

    • #52 Fix error when invoking with stdin source code instead of a filename
    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Dec 8, 2019)

    [v1.1.1]

    Added

    • Add pipenv-setup as a dev dependency & CI check to ensure synchronization between Pipfile and setup.py
    • Add tox configuration for local testing across Python versions
    • Add test for checking a single yield of TYP301 per function
    • Add coverage reporting to test suite
    • Add testing for positional only arguments

    Changed

    • typed_ast is now required only for Python versions < 3.8
    • Update flake8 minimum version to 3.7.9 for Python 3.8 compatibility
    • #50 Completely refactor test suite for maintainability

    Fixed

    • Fix mixed type hint tests not being run due to misnamed test class
    • Fix TYP301 classification issue where error is not yielded if the first argument is type annotated and the remaining arguments have type comments
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Sep 25, 2019)

    [v1.1.0]

    Added

    • #35: Issue templates
    • #36: Support for PEP 484-style type comments
    • #36: Add TYP301 for presence of type comment & type annotation for same entity
    • #36: Add error_code.from_function class method to generate argument for an entire function
    • #38: Improve setup.py metadata

    Fixed

    • #32: Incorrect line number for return values in the presence of multiline docstrings
    • #33: Improper handling of nested functions in class methods
    • setup.py dev dependencies out of sync with Pipfile
    • Incorrect order of arguments in Argument and Function __repr__ methods
    Source code(tar.gz)
    Source code(zip)
    flake8-annotations-1.1.0.tar.gz(11.43 KB)
    flake8_annotations-1.1.0-py3-none-any.whl(11.95 KB)
The strictest and most opinionated python linter ever!

wemake-python-styleguide Welcome to the strictest and most opinionated python linter ever. wemake-python-styleguide is actually a flake8 plugin with s

wemake.services 2.1k 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
Utilities for pycharm code formatting (flake8 and black)

Pycharm External Tools Extentions to Pycharm code formatting tools. Currently supported are flake8 and black on a selected code block. Usage Flake8 [P

Haim Daniel 13 Nov 03, 2022
A static-analysis bot for Github

Imhotep, the peaceful builder. What is it? Imhotep is a tool which will comment on commits coming into your repository and check for syntactic errors

Justin Abrahms 221 Nov 10, 2022
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
Custom Python linting through AST expressions

bellybutton bellybutton is a customizable, easy-to-configure linting engine for Python. What is this good for? Tools like pylint and flake8 provide, o

H. Chase Stevens 249 Dec 31, 2022
Reference implementation of sentinels for the Python stdlib

Sentinels This is a reference implementation of a utility for the definition of sentinel values in Python. This also includes a draft PEP for the incl

Tal Einat 22 Aug 27, 2022
Tool to check the completeness of MANIFEST.in for Python packages

check-manifest Are you a Python developer? Have you uploaded packages to the Python Package Index? Have you accidentally uploaded broken packages with

Marius Gedminas 270 Dec 26, 2022
Pylint plugin to enforce some secure coding standards for Python.

Pylint Secure Coding Standard Plugin pylint plugin that enforces some secure coding standards. Installation pip install pylint-secure-coding-standard

Nguyen Damien 2 Jan 04, 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
Tool for automatically reordering python imports. Similar to isort but uses static analysis more.

reorder_python_imports Tool for automatically reordering python imports. Similar to isort but uses static analysis more. Installation pip install reor

Anthony Sottile 589 Dec 26, 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
Tool for pinpointing circular imports in Python. Find cyclic imports in any project

Pycycle: Find and fix circular imports in python projects Pycycle is an experimental project that aims to help python developers fix their circular de

Vadim Kravcenko 311 Dec 15, 2022
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
mypy plugin for loguru

loguru-mypy A fancy plugin to boost up your logging with loguru mypy compatibility logoru-mypy should be compatible with mypy=0.770. Currently there

Tomasz Trębski 13 Nov 02, 2022
An open-source, mini imitation of GitHub Copilot for Emacs.

Second Mate An open-source, mini imitation of GitHub Copilot using EleutherAI GPT-Neo-2.7B (via Huggingface Model Hub) for Emacs. This is a much small

Sam Rawal 238 Dec 27, 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
Tool to automatically fix some issues reported by flake8 (forked from autoflake).

autoflake8 Introduction autoflake8 removes unused imports and unused variables from Python code. It makes use of pyflakes to do this. autoflake8 also

francisco souza 27 Sep 08, 2022
Mypy stubs for the PyQt5 framework

Mypy stubs for the PyQt5 framework This repository holds the stubs of the PyQt5 framework. It uses the stub files that are produced during compilation

62 Nov 22, 2022
OpenStack Hacking Style Checks. Mirror of code maintained at opendev.org.

Introduction hacking is a set of flake8 plugins that test and enforce the OpenStack StyleGuide Hacking pins its dependencies, as a new release of some

Mirrors of opendev.org/openstack 224 Jan 05, 2023