Skip to content

Modernize Type Hints: PEP 585 & PEP 604 #79

@zekunlou

Description

@zekunlou

Background

Python 3.7 introduced typing module aliases (List, Dict, Tuple, Optional, Union, etc.) as a workaround for built-in types not supporting generic subscript syntax at runtime. This is now superseded by two PEPs:

  • PEP 585 (Python 3.9): Built-in types (list, dict, tuple, ...) became directly generic, making typing.List etc. redundant. These aliases are soft-deprecated in 3.9 (which end of life on Oct 2025), emit deprecation warnings from 3.12, and will be removed in Python 3.14.
  • PEP 604 (Python 3.10): Introduces the X | Y union syntax, replacing the verbose Union[X, Y] and Optional[X] (X | None).

Changes

  • Drop from typing import List, Dict, Tuple, Optional, Union across the codebase; replace with built-in equivalents.
  • Adopt X | Y union syntax and X | None in place of Optional[X].
  • Enforce minimum Python version ≥ 3.10 to support the new union syntax natively at runtime.
  • Retain from typing import Literal, TypeVar, Protocol, etc., which have no built-in replacements.

Example diff:

# Before
from typing import Dict, List, Optional, Tuple, Union

def read_system(spelist: List[str]) -> Dict[str, int]: ...
def parse_index_str(s: Union[str, Literal["all"]]) -> Union[None, Tuple]: ...
def foo(x: Optional[str] = None): ...

# After
from typing import Literal

def read_system(spelist: list[str]) -> dict[str, int]: ...
def parse_index_str(s: str | Literal["all"]) -> None | tuple: ...
def foo(x: str | None = None): ...

Motivation

This is a non-functional, maintenance-only change. No computational logic is affected. It future-proofs the codebase against the Python 3.14 removal, reduces boilerplate imports, and improves readability.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions