Type Hinting: MyPy

Introduction

Type hinting and checking means providing type references and verifying that values in a program are used in a way consistent with their declared data types. While Python is dynamically typed, tools like mypy allow for static type checking without running the code.

Benefits of using type hints with mypy:

  • Detect type-related bugs early (without executing the program)

  • Improve code readability and editor support (e.g., autocompletion)

  • Encourage better documentation and long-term maintainability

Key Features

  • Static type checking at development time

  • Detects type mismatches, missing annotations, and more

  • Integrates well with editors and CI pipelines

  • Supports type inference, strict checking, and gradual typing

Installation

Install mypy using uv or pip:

uv add --dev mypy

Run mypy on your source files:

mypy src/

Configuration

To customize behavior, create a mypy.ini file in your project root. Here’s your current configuration:

[mypy]
python_version = 3.9
disallow_untyped_defs = true
ignore_missing_imports = true
  • python_version: Sets the Python version mypy should assume

  • disallow_untyped_defs: Requires all functions to have type annotations

  • ignore_missing_imports: Skips errors for third-party modules without stubs

Usage

Dynamic Typing in Python:

x = "hello"  # x is a str
x = 42       # now x is an int

Python allows this flexibility at runtime, but static checking helps avoid type bugs before deployment.

Incorrect Type Annotations

def add(a, b: int):
    """Add two integers."""
    print("Adding:", a, b)
    res = a + b
    return res

add(5, "hello")

Run:

mypy bad_test.py

Output:

bad_test.py:4: error: Function is missing a return type annotation  [no-untyped-def]
bad_test.py:4: error: Function is missing a type annotation for one or more arguments  [no-untyped-def]
bad_test.py:10: error: Argument 2 to "add" has incompatible type "str"; expected "int"  [arg-type]
Found 3 errors in 1 file (checked 1 source file)

Correct Type Annotations

Example 1:

def add(a: int, b: int) -> int:
    """Add two integers."""
    print("Adding:", a, b)
    res = a + b
    return res

add(5, 6)

Example 2:

from typing import Any

def add(a: int, b: int) -> Any:
    """Add two integers."""
    print("Adding:", a, b)
    res = a + b
    final_res = str(res)
    return final_res

add(5, 6)

Example 3:

def add(a: int, b: int) -> None:
    """Add two integers."""
    print("Adding:", a, b)
    res = a + b
    print("Result:", res)

add(5, 6)

Run:

mypy good_test.py

Output:

Success: no issues found in 1 source file

Additional Resources

Next Step

Once type checking is in place with mypy, the next step is to set up pre-commit to automatically run tools like ruff, mypy, and formatters before each commit. This helps enforce consistency and catch issues early in your workflow.

Uninstall

To uninstall mypy:

uv remove --dev mypy