Skip to content

Use a @dataclass for the Player test fake instead of a hand-written __init__ #640

Description

@nanotaboada

Problem

tests/player_fake.py defines the Player test fake as a plain class with an
eleven-parameter __init__ that assigns each argument to self. This is the
pattern a C#/Java developer reaches for (a POCO/POJO with an explicit
constructor), but in Python it is boilerplate the standard library generates
for you.

Two consequences:

  • Adding or renaming a player field means editing the parameter list, the
    assignments, and (potentially) call sites by hand.
  • Tests serialise the fake with player.__dict__ (e.g. client.post(PATH, json=player.__dict__)), reaching into a dunder attribute instead of a
    documented API.

Proposed Solution

Convert Player to a @dataclass. The decorator generates __init__,
__repr__, and __eq__ from the annotated fields. Replace player.__dict__
with dataclasses.asdict(player), the supported way to get a plain dict from a
dataclass instance.

from dataclasses import dataclass


@dataclass
class Player:
    """Test fake representing a Player."""

    id: str | None = None
    first_name: str | None = None
    middle_name: str | None = None
    last_name: str | None = None
    date_of_birth: str | None = None
    squad_number: int | None = None
    position: str | None = None
    abbr_position: str | None = None
    team: str | None = None
    league: str | None = None
    starting11: bool | None = None

The factory functions (existing_player(), nonexistent_player(),
unknown_player()) already use keyword arguments, so they stay unchanged. In
tests/test_main.py and tests/conftest.py, swap player.__dict__ for
asdict(player) — both produce the same flat, snake_case dict, so request
payloads do not change.

Suggested Approach

  1. Add from dataclasses import dataclass; decorate Player; delete the
    explicit __init__.
  2. Annotate every field with T | None and a = None default.
  3. Replace player.__dict__ with asdict(player) in tests/test_main.py and
    tests/conftest.py (from dataclasses import asdict).
  4. Run uv run pytest — all tests must stay green.

Acceptance Criteria

  • Player is a @dataclass with no hand-written __init__
  • All fields annotated with T | None syntax
  • No .__dict__ access remains in the test suite
  • Request payloads sent by tests are equivalent to before
  • All existing tests pass
  • CHANGELOG.md updated

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpriority:lowNice-to-have improvement. Can be deferred without blocking other work.pythonPull requests that update Python codepython:idiomsRefactors toward idiomatic Python (PEP conventions, stdlib idioms)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions