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

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions