Model/domain/addresses/user_address.py
Jun-te Kim 6198d7a46d postcode_splitter: pure domain (UserAddress, sanitise_postcode, postcode_batching)
Slice 1/6 of the postcode_splitter refactor (Hestia-Homes/Model#1100).
Introduces the pure-domain foundation under domain/, with no AWS, Postgres,
or pandas. UserAddress is a frozen dataclass that sanitises its postcode in
__post_init__ via the canonical sanitise_postcode helper, and
iter_postcode_grouped_batches preserves the legacy splitter's batching
invariants (group-by-postcode in insertion order, never split a group,
oversize single-postcode groups dispatched whole, final flush). Updates
UBIQUITOUS_LANGUAGE.md so the User Address term covers both the dataclass
sense (preferred in domain code) and the raw upstream-string sense.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 16:45:47 +00:00

36 lines
1.3 KiB
Python

"""The :class:`UserAddress` value object.
A frozen dataclass capturing the splitter's domain entity: the raw input
address line, a sanitised postcode, and an optional internal reference from
the customer dataset. Postcode sanitisation runs in ``__post_init__`` so no
caller can construct an instance with an un-normalised postcode.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Optional
from domain.postcodes.sanitise import sanitise_postcode
@dataclass(frozen=True)
class UserAddress:
"""A user-supplied address paired with its canonical postcode.
Attributes:
user_address: The free-text address string as supplied upstream.
postcode: The postcode; always stored in canonical form
(uppercased, whitespace stripped). Sanitisation is enforced by
:meth:`__post_init__`.
internal_reference: Optional customer-side identifier preserved for
traceability through the matching pipeline.
"""
user_address: str
postcode: str
internal_reference: Optional[str] = None
def __post_init__(self) -> None:
# Frozen dataclass: bypass the descriptor with object.__setattr__.
object.__setattr__(self, "postcode", sanitise_postcode(self.postcode))