Skip to content

Commit 60802f1

Browse files
derek73claude
andcommitted
Single-source the bare-string name_order guard
The identical TypeError lived in both Policy and PolicyPatch __post_init__ and could drift; extracted to a module helper. Also add the missing back-reference on Lexicon.__setstate__ pointing at its deliberately-duplicated twin in _types (the sync note was previously one-directional). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 79277de commit 60802f1

2 files changed

Lines changed: 15 additions & 12 deletions

File tree

nameparser/_lexicon.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ def __setstate__(self, state: dict[str, object]) -> None:
204204
# Fail at the unpickle site if the state comes from a different
205205
# Lexicon field layout (version skew) -- silently loading it
206206
# would defer the failure to some distant attribute read.
207+
# Message kept in sync with _types._guarded_setstate by design
208+
# (layering keeps this module import-free of _types).
207209
expected = {f.name for f in dataclasses.fields(Lexicon)} - {"_cap_map"}
208210
if set(state) != expected:
209211
missing = ", ".join(sorted(expected - set(state))) or "none"

nameparser/_policy.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ class PatronymicRule(StrEnum):
2828
_NAME_ROLES = frozenset({Role.GIVEN, Role.MIDDLE, Role.FAMILY})
2929

3030

31+
def _reject_bare_string_order(value: object) -> None:
32+
# tuple("gmf") would be ("g", "m", "f") -- catch the bare string
33+
# with the same TypeError every other iterable field raises.
34+
# Single-sourced: called from Policy AND PolicyPatch __post_init__.
35+
if isinstance(value, str):
36+
raise TypeError(
37+
f"name_order must be an iterable of three Roles, "
38+
f"not a bare string: {value!r}"
39+
)
40+
41+
3142
@dataclass(frozen=True, slots=True)
3243
class Policy:
3344
name_order: tuple[Role, Role, Role] = GIVEN_FIRST
@@ -50,13 +61,7 @@ class Policy:
5061
__setstate__ = _guarded_setstate
5162

5263
def __post_init__(self) -> None:
53-
# tuple("gmf") would be ("g", "m", "f") -- catch the bare string
54-
# with the same TypeError every other iterable field raises
55-
if isinstance(self.name_order, str):
56-
raise TypeError(
57-
f"name_order must be an iterable of three Roles, "
58-
f"not a bare string: {self.name_order!r}"
59-
)
64+
_reject_bare_string_order(self.name_order)
6065
order = tuple(self.name_order)
6166
if len(order) != 3 or set(order) != _NAME_ROLES:
6267
raise ValueError(
@@ -203,11 +208,7 @@ def __post_init__(self) -> None:
203208
# coerce a list at apply time, but the patch itself (and any
204209
# Locale holding it) must already be hashable.
205210
if self.name_order is not UNSET:
206-
if isinstance(self.name_order, str):
207-
raise TypeError(
208-
f"name_order must be an iterable of three Roles, "
209-
f"not a bare string: {self.name_order!r}"
210-
)
211+
_reject_bare_string_order(self.name_order)
211212
object.__setattr__(self, "name_order", tuple(self.name_order))
212213
for f in dataclasses.fields(self):
213214
if f.metadata.get("compose") != "union":

0 commit comments

Comments
 (0)