Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,34 @@ uv run sphinx-build -b html docs dist/docs
# so a copy spelled some other way is not undeclared but unseen. What
# covers those is _CORPUS_CLAIMS, which records what every rule claims
# -- its regex's corpus reach, its roles, and which names -- and so
# needs no notion of how a copy is spelled. Enrol the new ledger in
# _CORPUS_CLAIMS always, and in the others where they apply:
# needs no notion of how a copy is spelled.
# THREE rosters are keyed by FILENAME and checked by EQUALITY, so a new
# ledger must be enrolled in every one of them on the day it lands, even
# empty -- each fails loudly and names itself, but that is three separate
# red runs if you add them one at a time. Two more are keyed by rule
# CONTENT and apply only where such a rule exists.
# Required, by filename:
# - _SPAN_BEARING_RULES: add the filename, mapped to the set of issue
# tags whose rules carry a script-span class (empty set if none).
# - _CORPUS_CLAIMS: a ledger with no entry hard-fails. Add the
# filename mapped to {} while the ledger is empty, then one _Claim
# per rule as rules land. The test prints the values to record. A
# _Claim's digest moves whenever the corpus text does, so a pure
# RENAME of a corpus name lands here as names-unchanged,
# roles-unchanged, digest-moved; a count that GREW means the rule
# absorbed something.
# - _CROSS_RULE_WINNERS: add the filename mapped to {} while the
# ledger has no contested name. Equality since #452, which found
# that a ledger with no rows had been indistinguishable from one
# needing none -- the two 2.x ledgers whose shapes #452 moved
# between rules had no section at all.
# Conditional, by rule content:
# - _HONORIFIC_SOURCES: if the ledger has a CJK honorific rule, add a
# substring of its issue (keyed that way, not by tag) mapped to the
# constant it copies -- but only if no existing key already matches
# that issue. A retroactive ledger can repeat an older one's rule
# verbatim (fix(#271/#272/#298) is in both today), and every rule
# must match exactly one key.
# - _CORPUS_CLAIMS: REQUIRED, not conditional -- a ledger with no
# entry hard-fails. Add the filename mapped to {} while the ledger
# is empty, then one _Claim per rule as rules land. The test prints
# the values to record.
# - _LATIN_ALTERNATION_SOURCES: same, for a rule copying a Latin
# vocabulary (maiden markers, ambiguous acronyms). An alternation
# matching no key fails as undeclared -- add it, or record it in
Expand Down
2 changes: 2 additions & 0 deletions docs/release_log.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
Release Log
===========
* 2.3.0 - Unreleased

* 2.2.0 - August 31, 2026

nameparser 2.2 is a rename plus about thirty parsing fixes.
Expand Down
6 changes: 3 additions & 3 deletions nameparser/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
#: cannot carry the dev marker, so `VERSION >= (2, 2, 0)` is already
#: true here while 2.2.0 is unreleased. Compare `__version__` instead
#: where that distinction matters.
VERSION = (2, 2, 0)
VERSION = (2, 3, 0)
#: PEP 440 pre-release/dev segment appended to the numeric version, or
#: "" for a final release. Joined WITHOUT a dot ("2.0.0rc1", not
#: "2.0.0.rc1"); setuptools reads __version__ as the package version.
#:
#: "dev" through the cycle, cleared at release. It normalizes to
#: 2.2.0.dev0, which sorts above 2.1.0 and BELOW 2.2.0, so an install
#: 2.3.0.dev0, which sorts above 2.2.0 and BELOW 2.3.0, so an install
#: from master can never masquerade as the release it precedes.
PRE_RELEASE = ""
PRE_RELEASE = "dev"
__version__ = ".".join(map(str, VERSION)) + PRE_RELEASE
5 changes: 4 additions & 1 deletion tests/v2/test_ledger_guards.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,8 @@ def test_script_ranges_membership_is_decided() -> None:
"fix(#271/#272/#298)", # the canonical class
"fix(#298)", # the 间隔号 lookahead
}),
"expected_since_2.1.0.toml": frozenset(), # open cycle, no rules yet
"expected_since_2.1.0.toml": frozenset(), # 2.2 cycle: no span-bearing rule
"expected_since_2.2.0.toml": frozenset(), # open cycle, no rules yet
}

#: The leading `fix(...)`/`feat(...)` tag of a rule's `issue`, which is
Expand Down Expand Up @@ -1776,6 +1777,7 @@ def _claim(rule: dict) -> _Claim:
"fix(#371) a suffix never begins a name: the Ph./D. merge declines at the head":
_Claim(4, ('family', 'given', 'middle', 'suffix', 'title'), "1425d85a2d86"),
},
"expected_since_2.2.0.toml": {}, # open cycle, no rules yet
"expected_since_2.1.0.toml": {
"fix(#371) a suffix never begins a name: the Ph./D. merge declines at the head":
_Claim(4, ('family', 'given', 'middle', 'suffix', 'title'), "1425d85a2d86"),
Expand Down Expand Up @@ -1973,6 +1975,7 @@ def test_every_rule_claims_the_recorded_share_of_the_corpus() -> None:
#: Re-measure rather than adjust them if a parser change moves one:
#: a diff shape that shifted is a finding, not a number to update.
_CROSS_RULE_WINNERS: dict[str, dict[tuple[str, tuple[str, ...]], str]] = {
"expected_since_2.2.0.toml": {}, # open cycle, no rules and so no contest
"expected_since_1.4.0.toml": {
("Andrews, M.D.", ("given", "suffix")): "fix(comma-family)",
("田中, 太郎さん", ("given", "suffix")): "fix(cjk-comma-honorific-peel)",
Expand Down
2 changes: 1 addition & 1 deletion tools/differential/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
FIELDS = ("title", "first", "middle", "last", "suffix", "nickname",
"maiden")

DEFAULT_BASELINE = "2.1.0"
DEFAULT_BASELINE = "2.2.0"
REPO_ROOT = HERE.parents[1]
#: The v2 API's names for the same seven roles FIELDS names in v1
#: vocabulary. Both are compared from baseline 2.0 on.
Expand Down
34 changes: 34 additions & 0 deletions tools/differential/expected_since_2.2.0.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Ledger for baseline 2.2.0 -- what changes for a user upgrading from
# the previous minor. Same rule grammar as the other ledgers: `issue`,
# `name_regex` and `fields` are every one of them required. Neither
# narrowing key may stand on its own -- #451 banned a rule with
# `fields` and no regex, #456 banned the reverse -- so a rule here
# narrows by name AND by role, never by just one.
#
# Opened empty the day 2.2.0 shipped (AGENTS.md release step 8), and it
# is opened before it has anything to say because DEFAULT_BASELINE and
# the ledger are coupled: _allowlist_for treats a missing file as a
# hard error, on the reasoning that an absent ledger classifies nothing
# and would make every diff report as unexplained. So the baseline
# could not advance to 2.2.0 without this file.
#
# Do not copy rules across from expected_since_2.1.0.toml: that ledger
# classifies what 2.2 changed on top of 2.1, and a rule copied without
# checking either over-matches -- hiding a real 2.3 regression behind a
# 2.2-era label -- or never fires at all. Where a 2.3 change is visible
# from several baselines the rule may legitimately appear in more than
# one file, but each copy is checked against its own run rather than
# assumed.
#
# tests/v2/test_differential.py permits exactly one empty ledger, the
# one DEFAULT_BASELINE names -- which is this file, for as long as the
# 2.3 cycle moves no corpus name at the default order.
#
# tests/v2/test_ledger_guards.py records this file in
# _SPAN_BEARING_RULES with an empty set and in _CORPUS_CLAIMS with an
# empty mapping. The first rule that hand-copies _SCRIPT_RANGES has to
# be recorded in the former or the sweep fails.
#
# There is deliberately no `change = []` line. TOML forbids appending a
# [[change]] table to a statically defined array, so that line would
# block the first entry.