From 4f3fe146de9b22430dc04f486a71fc90e3424528 Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Sat, 11 Jul 2026 18:58:43 -0700 Subject: [PATCH 1/2] Reframe shared CONSTANTS as an application-startup contract The docs taught the None sentinel and the shared-instance gotcha as surprising properties of the API. State the actual contract instead: CONSTANTS is for application-level configuration set once at startup -- the same role logging and locale play, since it's the only channel that reaches parses in code you don't own. Anything scoped to one dataset, one library, or one test should get its own Constants instance instead. The "Potential Gotcha" framing in both customize.rst and the config module docstring is now presented as a consequence of mixing the two up, not a surprise. No behavior change -- docs only. Fixes #262. --- docs/customize.rst | 23 ++++++++++++++++------- nameparser/config/__init__.py | 27 ++++++++++++++++----------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/docs/customize.rst b/docs/customize.rst index 7b05120..cb7cf55 100644 --- a/docs/customize.rst +++ b/docs/customize.rst @@ -1,6 +1,14 @@ Customizing the Parser with Your Own Configuration ================================================== +:py:class:`~nameparser.config.Constants` is for application-level +configuration, set once at startup: the shared module-level ``CONSTANTS`` +instance is the only channel that reaches parses happening in code you don't +own -- helpers, pipelines, a third-party library using nameparser internally +-- the same role ``logging`` and ``locale`` play elsewhere. For anything +scoped to one dataset, one library, or one test, pass your own ``Constants`` +instance instead; see "Module-level Shared Configuration Instance" below. + Recognition of titles, prefixes, suffixes and conjunctions is handled by matching the lower case characters of a name piece with pre-defined sets of strings located in :py:mod:`nameparser.config`. You can adjust @@ -428,13 +436,14 @@ making them lower case and removing periods. Module-level Shared Configuration Instance ------------------------------------------ -When you modify the configuration, by default this will modify the behavior all -HumanName instances. This could be a handy way to set it up for your entire -project, but it could also lead to some unexpected behavior because changing -the config on one instance could modify the behavior of another instance. -Parsing itself never modifies the configuration — only your own ``add`` and -``remove`` calls do — so the shared instance is safe to read concurrently, -e.g. parsing names on multiple threads. +As established above, ``CONSTANTS`` is shared by every ``HumanName`` created +without its own config -- that's what makes it the right place for +application-level setup, and also the source of the one gotcha it carries: +changing the config on one instance changes the behavior of every other +instance that shares it, which can be surprising if you only meant to +configure the one you're holding. Parsing itself never modifies the +configuration — only your own ``add`` and ``remove`` calls do — so the shared +instance is safe to read concurrently, e.g. parsing names on multiple threads. .. doctest:: module config :options: +ELLIPSIS, +NORMALIZE_WHITESPACE diff --git a/nameparser/config/__init__.py b/nameparser/config/__init__.py index 342fd6e..5d61861 100644 --- a/nameparser/config/__init__.py +++ b/nameparser/config/__init__.py @@ -1,20 +1,24 @@ """ The :py:mod:`nameparser.config` module manages the configuration of the -nameparser. +nameparser. -A module-level instance of :py:class:`~nameparser.config.Constants` is created -and used by default for all HumanName instances. You can adjust the entire module's -configuration by importing this instance and changing it. +:py:class:`~nameparser.config.Constants` is for application-level +configuration, set once at startup. ``CONSTANTS``, the module-level instance +used by every ``HumanName`` created without its own config, is the only +channel that reaches parses happening in code you don't own (helpers, +pipelines, a third-party library using nameparser internally) -- the same +role ``logging`` and ``locale`` play elsewhere. Import it and change it +directly: :: >>> from nameparser.config import CONSTANTS >>> CONSTANTS.titles.remove('hon').add('chemistry','dean') # doctest: +SKIP -You can also adjust the configuration of individual instances by passing -your own :py:class:`Constants` instance as the second argument upon -instantiation -- ``Constants()`` for fresh library defaults, or -``CONSTANTS.copy()`` for a private snapshot of the current module config. +For anything scoped -- one dataset, one library, one test -- pass your own +:py:class:`Constants` instance as the second argument upon instantiation +instead: ``Constants()`` for fresh library defaults, or ``CONSTANTS.copy()`` +for a private snapshot of the current module config. :: @@ -24,9 +28,10 @@ >>> hn.C.titles.add('dean') # doctest: +SKIP >>> hn.parse_full_name() # need to run this again after config changes -**Potential Gotcha**: If you do not pass your own :py:class:`Constants` -instance as the second argument, ``hn.C`` will be a reference to the module -config, possibly yielding unexpected results. See `Customizing the Parser +Mixing the two up is where the surprises come from, not the API itself: if +you do not pass your own :py:class:`Constants` instance as the second +argument, ``hn.C`` will be a reference to the module config, and a change +there reaches every other instance sharing it. See `Customizing the Parser `_. .. deprecated:: 1.4.0 From 381ca36706a3664664f0d4b3941ba70e4510cdd9 Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Sat, 11 Jul 2026 19:33:07 -0700 Subject: [PATCH 2/2] Clarify the "see below" pointer in the new customize.rst lead-in The pointer sent readers to "Module-level Shared Configuration Instance" for private-config guidance, but that section title reads as being about the shared instance, not the private alternative -- name what's actually there (the three explicit forms) instead. Found in review of #283. --- docs/customize.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/customize.rst b/docs/customize.rst index cb7cf55..da1b8dc 100644 --- a/docs/customize.rst +++ b/docs/customize.rst @@ -7,7 +7,8 @@ instance is the only channel that reaches parses happening in code you don't own -- helpers, pipelines, a third-party library using nameparser internally -- the same role ``logging`` and ``locale`` play elsewhere. For anything scoped to one dataset, one library, or one test, pass your own ``Constants`` -instance instead; see "Module-level Shared Configuration Instance" below. +instance instead -- see the three explicit forms under "Module-level Shared +Configuration Instance" below. Recognition of titles, prefixes, suffixes and conjunctions is handled by matching the lower case characters of a name piece with pre-defined sets