#226 added validation of the constants argument in HumanName.__init__, but C is a plain attribute, so post-construction assignment bypasses it entirely:
from nameparser import HumanName
hn = HumanName('John Doe')
hn.C = 'garbage' # accepted silently
hn.full_name = 'Dr John Smith'
# AttributeError: 'str' object has no attribute 'regexes'
# — raised deep inside collapse_whitespace, no mention of C
The error surfaces at the wrong layer with no pointer to the actual mistake.
Fix: make C a property whose setter reuses the constructor's check (extract a shared _validate_constants helper) so both assignment paths give the same immediate TypeError.
Related detail once this is fixed at the source: the pickle sentinel in __getstate__/__setstate__ maps C is CONSTANTS to None and any None back to CONSTANTS, so an instance whose C was corrupted to None via this bypass currently round-trips to the shared singleton — silently "healing" the corruption and flipping has_own_config. A dedicated module-level sentinel object instead of None would remove that ambiguity; likely moot if the setter validation lands.
Found by review of PR #237 — pre-existing, unrelated to that change.
#226 added validation of the
constantsargument inHumanName.__init__, butCis a plain attribute, so post-construction assignment bypasses it entirely:The error surfaces at the wrong layer with no pointer to the actual mistake.
Fix: make
Ca property whose setter reuses the constructor's check (extract a shared_validate_constantshelper) so both assignment paths give the same immediateTypeError.Related detail once this is fixed at the source: the pickle sentinel in
__getstate__/__setstate__mapsC is CONSTANTStoNoneand anyNoneback toCONSTANTS, so an instance whoseCwas corrupted toNonevia this bypass currently round-trips to the shared singleton — silently "healing" the corruption and flippinghas_own_config. A dedicated module-level sentinel object instead ofNonewould remove that ambiguity; likely moot if the setter validation lands.Found by review of PR #237 — pre-existing, unrelated to that change.