Skip to content

Commit 4f3fe14

Browse files
committed
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.
1 parent 18c9b6a commit 4f3fe14

2 files changed

Lines changed: 32 additions & 18 deletions

File tree

docs/customize.rst

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
Customizing the Parser with Your Own Configuration
22
==================================================
33

4+
:py:class:`~nameparser.config.Constants` is for application-level
5+
configuration, set once at startup: the shared module-level ``CONSTANTS``
6+
instance is the only channel that reaches parses happening in code you don't
7+
own -- helpers, pipelines, a third-party library using nameparser internally
8+
-- the same role ``logging`` and ``locale`` play elsewhere. For anything
9+
scoped to one dataset, one library, or one test, pass your own ``Constants``
10+
instance instead; see "Module-level Shared Configuration Instance" below.
11+
412
Recognition of titles, prefixes, suffixes and conjunctions is handled by
513
matching the lower case characters of a name piece with pre-defined sets
614
of strings located in :py:mod:`nameparser.config`. You can adjust
@@ -428,13 +436,14 @@ making them lower case and removing periods.
428436
Module-level Shared Configuration Instance
429437
------------------------------------------
430438

431-
When you modify the configuration, by default this will modify the behavior all
432-
HumanName instances. This could be a handy way to set it up for your entire
433-
project, but it could also lead to some unexpected behavior because changing
434-
the config on one instance could modify the behavior of another instance.
435-
Parsing itself never modifies the configuration — only your own ``add`` and
436-
``remove`` calls do — so the shared instance is safe to read concurrently,
437-
e.g. parsing names on multiple threads.
439+
As established above, ``CONSTANTS`` is shared by every ``HumanName`` created
440+
without its own config -- that's what makes it the right place for
441+
application-level setup, and also the source of the one gotcha it carries:
442+
changing the config on one instance changes the behavior of every other
443+
instance that shares it, which can be surprising if you only meant to
444+
configure the one you're holding. Parsing itself never modifies the
445+
configuration — only your own ``add`` and ``remove`` calls do — so the shared
446+
instance is safe to read concurrently, e.g. parsing names on multiple threads.
438447

439448
.. doctest:: module config
440449
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE

nameparser/config/__init__.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
"""
22
The :py:mod:`nameparser.config` module manages the configuration of the
3-
nameparser.
3+
nameparser.
44
5-
A module-level instance of :py:class:`~nameparser.config.Constants` is created
6-
and used by default for all HumanName instances. You can adjust the entire module's
7-
configuration by importing this instance and changing it.
5+
:py:class:`~nameparser.config.Constants` is for application-level
6+
configuration, set once at startup. ``CONSTANTS``, the module-level instance
7+
used by every ``HumanName`` created without its own config, is the only
8+
channel that reaches parses happening in code you don't own (helpers,
9+
pipelines, a third-party library using nameparser internally) -- the same
10+
role ``logging`` and ``locale`` play elsewhere. Import it and change it
11+
directly:
812
913
::
1014
1115
>>> from nameparser.config import CONSTANTS
1216
>>> CONSTANTS.titles.remove('hon').add('chemistry','dean') # doctest: +SKIP
1317
14-
You can also adjust the configuration of individual instances by passing
15-
your own :py:class:`Constants` instance as the second argument upon
16-
instantiation -- ``Constants()`` for fresh library defaults, or
17-
``CONSTANTS.copy()`` for a private snapshot of the current module config.
18+
For anything scoped -- one dataset, one library, one test -- pass your own
19+
:py:class:`Constants` instance as the second argument upon instantiation
20+
instead: ``Constants()`` for fresh library defaults, or ``CONSTANTS.copy()``
21+
for a private snapshot of the current module config.
1822
1923
::
2024
@@ -24,9 +28,10 @@
2428
>>> hn.C.titles.add('dean') # doctest: +SKIP
2529
>>> hn.parse_full_name() # need to run this again after config changes
2630
27-
**Potential Gotcha**: If you do not pass your own :py:class:`Constants`
28-
instance as the second argument, ``hn.C`` will be a reference to the module
29-
config, possibly yielding unexpected results. See `Customizing the Parser
31+
Mixing the two up is where the surprises come from, not the API itself: if
32+
you do not pass your own :py:class:`Constants` instance as the second
33+
argument, ``hn.C`` will be a reference to the module config, and a change
34+
there reaches every other instance sharing it. See `Customizing the Parser
3035
<customize.html>`_.
3136
3237
.. deprecated:: 1.4.0

0 commit comments

Comments
 (0)