Skip to content

docs: add Python type hints best practices guide#4

Open
agent-kurouto[bot] wants to merge 3 commits intodevfrom
eywalker/plt-1024-test-verify-slack-message-cleanup-throttled-text-threaded
Open

docs: add Python type hints best practices guide#4
agent-kurouto[bot] wants to merge 3 commits intodevfrom
eywalker/plt-1024-test-verify-slack-message-cleanup-throttled-text-threaded

Conversation

@agent-kurouto
Copy link
Contributor

@agent-kurouto agent-kurouto bot commented Mar 19, 2026

Summary

  • Add docs/type-hints.md: a comprehensive deep-dive guide on Python type hints best practices, following the same format as docs/logging.md
  • Guide covers 10 sections: why type hints matter, basic syntax, modern union/generic syntax (3.9/3.10+), typing module essentials (TypeAlias, Callable, Literal, TypedDict, overload), Protocols & structural subtyping, Generics & TypeVar, runtime vs. static typing, Pyright configuration, special cases (dataclasses, NamedTuple, Self, generators, async), and common anti-patterns
  • Update python/best-practices.md Section 2 with a cross-reference link to the new guide, mirroring the pattern used for docs/logging.md

Test plan

  • Review docs/type-hints.md for accuracy and completeness
  • Verify cross-reference link in python/best-practices.md Section 2 resolves correctly
  • Confirm document follows the same formatting conventions as docs/logging.md

Closes PLT-1024

🤖 Generated with Claude Code

Add docs/type-hints.md with a comprehensive deep-dive on type hints:
modern syntax, typing module essentials, Protocols, Generics, Pyright
configuration, special cases (dataclasses, overloads, generators), and
common anti-patterns. Cross-reference the guide from Section 2 of
python/best-practices.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@eywalker eywalker requested a review from Copilot March 19, 2026 10:45
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a dedicated documentation guide for Python type-hinting best practices and links to it from the existing Python best-practices doc, aligning with the existing “Logging Guide” cross-reference pattern.

Changes:

  • Add docs/type-hints.md with a 10-section deep-dive on Python typing best practices.
  • Add a cross-reference link in python/best-practices.md pointing readers to the new guide.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
python/best-practices.md Adds a “Type Hints Guide” cross-reference link in the type-hints section.
docs/type-hints.md New comprehensive type-hints best-practices guide (syntax, typing constructs, protocols/generics, pyright, and anti-patterns).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +326 to +333
from typing import TypeVar
from numbers import Number

Numeric = TypeVar("Numeric", int, float, complex) # union constraint
Comparable = TypeVar("Comparable", bound="SupportsLessThan") # upper bound

def maximum(a: Numeric, b: Numeric) -> Numeric:
return a if a > b else b
Comment on lines +590 to +595
from typing import TypeVarTuple, Unpack

Ts = TypeVarTuple("Ts")

def broadcast(func: Callable[[Unpack[Ts]], None], *args: Unpack[Ts]) -> None:
func(*args)
Comment on lines +642 to +654
# Avoid — loses all type safety
def process(data: Any) -> Any:
return data["value"]

# Prefer — even a broad type is better than Any
def process(data: dict[str, object]) -> object:
return data["value"]

# Use Any sparingly, document why
def parse_legacy_response(raw: bytes) -> Any:
# Legacy API returns inconsistent shapes; typed in follow-up issue #42
return json.loads(raw)
```

# Avoid (legacy)
from typing import Optional, Union
def process(value: Union[int, str, None]) -> List[str]: ...
Comment on lines +119 to +125
For Python 3.7–3.9, add this import at the top of any module to enable the 3.10+ union syntax and forward references without quotes. It makes all annotations strings (lazy evaluation), so they don't affect runtime performance.

```python
from __future__ import annotations

def build(parts: list[str], separator: str | None = None) -> str:
return (separator or "").join(parts)
Comment on lines +139 to +144
from typing import TypeAlias

# Give a meaningful name to a complex type
Headers: TypeAlias = dict[str, str]
Callback: TypeAlias = Callable[[int, str], bool]
Matrix: TypeAlias = list[list[float]]
Comment on lines +152 to +161
from typing import Callable

# Callable[[arg_types...], return_type]
Handler: TypeAlias = Callable[[str, int], bool]

def register(event: str, handler: Callable[[str], None]) -> None: ...

# No-argument callable returning nothing
Thunk: TypeAlias = Callable[[], None]
```
Address 7 review comments from Copilot:

- `TypeAlias` snippet: add missing `Callable` import
- `Callable` snippet: add missing `TypeAlias` import
- Legacy union snippet: add missing `List` import
- Bounded TypeVar: define `SupportsLessThan` Protocol, drop unorderable
  `complex` from the union constraint, use `<` instead of `>` for the
  comparable example
- `Unpack`/`TypeVarTuple` snippet: add missing `Callable` import
- `Any` anti-pattern snippet: add missing `import json` and
  `from typing import Any`
- `from __future__ import annotations` section: rewrite to clarify it
  postpones evaluation / enables forward refs without quotes, but does
  NOT enable `X | Y` syntax on Python 3.7–3.9 (that requires 3.10+)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@agent-kurouto
Copy link
Contributor Author

agent-kurouto bot commented Mar 19, 2026

Self-Review Notes

Overall this is a solid, well-structured guide. Here are a few observations from a fresh pass:

✅ Strengths

  • The 10-section structure flows logically from basics → modern syntax → advanced features → anti-patterns
  • Code examples consistently use the "Prefer / Avoid" pattern, which is easy to scan
  • The Pyright CI and pre-commit integration snippets are immediately actionable
  • ParamSpec, TypeVarTuple, and Self coverage is often missing from type hint guides — nice to have them here

🔍 Minor Observations

  • from __future__ import annotations appears in two places (Section 3 and Section 7 under TYPE_CHECKING) — the two mentions are complementary but could benefit from a short cross-reference between them so readers don't miss the connection
  • NewType is not covered — it's a common source of confusion (zero runtime cost, semantic distinct IDs) and worth a brief entry in Section 4 alongside TypeAlias
  • TypeGuard and assert_never are absent — these are frequently used for exhaustive matching patterns and would round out the narrowing story in Section 4/9
  • Annotated is not mentioned — especially relevant given Pydantic v2 and FastAPI are referenced in Section 7; a short example showing Annotated[int, Gt(0)] would tie that section together
  • Further Reading is missing PEP 612 (ParamSpec), PEP 646 (TypeVarTuple), and PEP 673 (Self), which are all covered in the guide body

💡 Ideas for Future Topics

Based on what this repo already covers (type hints, logging), here are natural next guides to add:

Topic Why it fits
Testing Best Practices pytest fixtures, parametrize, hypothesis for property-based testing, mocking strategies — one of the most-asked-about areas
Error Handling & Exception Design Custom exception hierarchies, when to use raise from, ExceptionGroup (3.11+), structured error contracts
Async / asyncio Best Practices async/await patterns, TaskGroup, cancellation hygiene, avoiding common pitfalls like blocking the event loop
Dependency Management with uv pyproject.toml structure, lock files, workspace layout, CI caching — complements the Pyright setup already shown here
Dataclasses vs Pydantic vs attrs Decision guide with a comparison matrix — when to reach for each, migration patterns
Python Security Practices Input validation, secrets handling, dependency auditing (pip-audit), SAST tooling
CLI Design with Typer / Click Building well-typed, testable CLI tools — pairs naturally with the type hints guide
Code Architecture & Dependency Injection Module boundaries, DI patterns without heavy frameworks, avoiding circular imports at scale

The Testing and Error Handling topics would probably have the highest immediate value for teams adopting this guide.

🤖 Generated with Claude Code

…rt_never, Annotated, cross-refs

- Add `NewType` subsection to Section 4: zero-runtime-cost semantic type
  distinctions with worked example showing UserId vs OrderId mixing error
- Add `TypeGuard` subsection: custom narrowing predicates with a
  list[object] → list[str] guard example
- Add `assert_never` subsection: exhaustive Literal/Union matching with
  a Status literal example; explains how Pyright surfaces unhandled variants
- Add `Annotated` subsection: embedding Pydantic v2 Field constraints and
  FastAPI Path/Query constraints directly in type annotations
- Add cross-reference from the `from __future__ import annotations` section
  (Section 3) pointing readers to the TYPE_CHECKING section (Section 7)
- Expand Table of Contents entry for Section 4 with all new subsection names
- Add PEP 593 (Annotated), PEP 612 (ParamSpec), PEP 646 (TypeVarTuple),
  and PEP 673 (Self) to Further Reading

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant