You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
constants=None means "construct a fresh private Constants()" — a sentinel that means the opposite of what None conventionally means (the default here is the shared config), documented under a "Potential Gotcha" heading. 1.4 ships the explicit vocabulary and the deprecation warning; removal is #261 (2.0).
HumanName(name) # shared CONSTANTS (unchanged)HumanName(name, constants=Constants()) # private, library defaultsHumanName(name, constants=CONSTANTS.copy()) # private, snapshot of current shared config
The trap the sentinel can't express
"Give me a private config" is ambiguous between fresh library defaults and a private snapshot of the current shared config. None silently picks the first: customize CONSTANTS.titles, later pass None for "my own config", and the customizations are gone with no error. An explicit Constants argument forces the caller to answer the question; the missing piece is a nice spelling for the snapshot answer — copy.deepcopy(CONSTANTS) works (reliably since the 1.3.0 pickle/deepcopy fixes, which is what makes this cheap now), but nobody discovers deepcopy for config.
Checklist
Add Constants.copy() — deepcopy-based detached copy; _on_change rewiring is already handled by the deepcopy machinery landed in 1.3.0
DeprecationWarning when constants=None is passed explicitly, naming both replacements. Only explicitNone warns — the signature default is CONSTANTS, so omitting the argument never hits the branch
Update the signature annotation in the same PR (Constants | None stays for 1.4, docstring marks None deprecated)
Docs in the same PR: the three-spelling vocabulary in customize.rst and a sentence on the defaults-vs-snapshot distinction
Activity
Restore v1.3/1.4 manager hardening in the shim (#221/#238/#241/#242/#260