Every Iterable[str] parameter on Constants.__init__ accepts a bare str, which is an iterable — of characters. SetManager.__init__ (config/init.py, self.elements = set(elements)) then builds a set of single characters, silently replacing the entire default set.
Repro:
from nameparser import HumanName
from nameparser.config import Constants
c = Constants(titles='dr')
c.titles # SetManager({'d', 'r'}) — 600+ defaults gone
HumanName('Dr John Smith', constants=c)
# title='', first='Dr', last='Smith' — silently wrong, no error anywhere
The same applies to all SetManager-backed keyword arguments. This is the same pattern family as #226: caller hands in configuration, the library silently destroys the intent. Debugging it later means diffing large constant sets.
Fix: reject str/bytes in SetManager.__init__ (or at the Constants.__init__ boundary) with a TypeError suggesting the fix, e.g. expected an iterable of strings, got a single string — wrap it: ['dr'].
Found by review of PR #237 — pre-existing, unrelated to that change.
Every
Iterable[str]parameter onConstants.__init__accepts a barestr, which is an iterable — of characters.SetManager.__init__(config/init.py,self.elements = set(elements)) then builds a set of single characters, silently replacing the entire default set.Repro:
The same applies to all SetManager-backed keyword arguments. This is the same pattern family as #226: caller hands in configuration, the library silently destroys the intent. Debugging it later means diffing large constant sets.
Fix: reject
str/bytesinSetManager.__init__(or at theConstants.__init__boundary) with aTypeErrorsuggesting the fix, e.g.expected an iterable of strings, got a single string — wrap it: ['dr'].Found by review of PR #237 — pre-existing, unrelated to that change.