flake8-annotations-complexity
An extension for flake8 to report on excessively complex type annotations. Complex type annotations often indicate suboptimal annotation usage, poor code decomposition, or an improper choice of data structure, making the code harder to read. The plugin calculates annotation complexity based on the maximum nesting level (e.g., `List[int]` is 2, `Tuple[List[Optional[str]], int]` is 4). The current version is 0.1.0, and it receives infrequent but active maintenance.
Warnings
- breaking Version 0.1.0 of `flake8-annotations-complexity` officially drops support for Python 3.7 and 3.8. Projects using these Python versions must upgrade to Python 3.9 or newer to use this version of the plugin or stick to an older plugin version.
- gotcha The default maximum annotation complexity is 3. This can be surprisingly low for common, slightly nested types like `List[Dict[str, int]]` (complexity 3) or `Dict[str, List[Union[int, str]]]` (complexity 4). Be aware of this default and adjust it using the `--max-annotations-complexity` option in your `flake8` configuration (e.g., `setup.cfg`, `pyproject.toml`) if it's too restrictive for your codebase.
- gotcha The plugin counts `typing.Annotated` wrappers towards annotation complexity. If you're using `Annotated` (PEP-593) for adding metadata (e.g., with Pydantic fields), types like `Annotated[dict[str, Model], Field(...)]` might be flagged as too complex even if the underlying type's structure is not inherently complex.
- gotcha The plugin currently only implements a single rule (`TAE002`) for annotation complexity. This means there's no built-in differentiation in complexity checks between various annotation contexts (e.g., function arguments vs. return types vs. variable annotations).
Install
-
pip install flake8-annotations-complexity
Quickstart
import os
from typing import List, Dict, Union, Optional
# Create a dummy Python file to lint
python_code = '''
# test_complexity.py
from typing import List, Dict, Union, Optional
def func_with_complex_annotation(
data: Dict[str, List[Union[int, Optional[str]]]]
) -> Dict[str, List[Union[int, Optional[str]]]]:
"""A function with a very complex type annotation."""
return data
def func_with_medium_annotation(
config: Dict[str, List[str]]
) -> None:
"""A function with a medium-complexity annotation."""
pass
def func_with_simple_annotation(
name: str, age: int
) -> str:
"""A function with simple annotations."""
return f"{name} is {age} years old"
'''
with open('test_complexity.py', 'w') as f:
f.write(python_code)
# Run flake8 with the plugin
print("\n--- Running flake8 with default max-annotations-complexity (3) ---")
os.system("flake8 test_complexity.py")
print("\n--- Running flake8 with max-annotations-complexity set to 4 ---")
os.system("flake8 --max-annotations-complexity=4 test_complexity.py")
# Clean up the dummy file
os.remove('test_complexity.py')