Skip to content

Coverage metrics

Python type annotations are optional: unannotated code runs fine. As projects grow, missing annotations make it harder for type checkers to catch bugs, for IDEs to give accurate completions, and for contributors to read the code.

typestats measures the type-coverage of Python packages: the percentage of public symbols with type annotations.

Typable

Each annotation slot is counted individually: function parameters, return types, variable annotations, class attributes, and method signatures each contribute one slot. Functions and classes are not counted as single items.

x: int = 0
z: Any = 2


def greet(name: str, greeting: Any) -> str: ...


class Config:
    debug: bool
    timeout: Any
    retries = default_retries()

    def __init__(self, name: str) -> None:
        self.name = name

    def validate(self) -> bool: ...
Symbol Type typed any typable
attr x int 1 0 1
attr z Any 1 1 1
func greet
param name str 1 0 1
param greeting Any 1 1 1
return str 1 0 1
class Config
attr debug bool 1 0 1
attr timeout Any 1 1 1
attr retries 0 0 1
meth __init__
↳↳ param name str 1 0 1
↳↳ return None 1 0 1
attr name 0 0 1
meth validate
↳↳ return bool 1 0 1
Total 10 3 12

Note that self is excluded because type-checkers do not require it to be annotated.

Unlike mypy and pyright, typestats does not treat types from the stdlib or unknown third-party packages as Any. If a parameter is annotated x: ArrayLike, it counts as typed regardless of whether ArrayLike can be resolved.

Coverage

Whether a symbol is annotated is only half the story: Any satisfies the type checker syntactically, yet provides zero type safety. That is why typestats reports two coverage metrics.

  • Coverage: typed / typable
  • Coverage (strict): (typed - any) / typable

Non-strict coverage counts Any as typed: it shows how much of the API is annotated at all. Strict coverage excludes Any, counting only annotations a type checker can use. Since Any provides no type safety, typestats provides this additional strict coverage metric.

From the example above:

  • Coverage: 10 / 12 = 83%
  • Coverage (strict): (10 - 3) / 12 = 58%

The 25-point gap (3 / 12) is the Any share of the annotations.