diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index cb5369e..999f252 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -40,7 +40,7 @@ jobs: run: mypy - name: Run Tests run: | - python tests.py + pytest python -m build --sdist twine check dist/* sphinx-build -b html docs dist/docs diff --git a/AGENTS.md b/AGENTS.md index 536332e..47f6293 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,13 +9,14 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co pip install --group dev # Run all tests -python tests.py +pytest -# Run a single test by class/method -python -m unittest tests.HumanNamePythonTests.test_utf8 +# Run a single test file / class / method +pytest tests/test_python_api.py +pytest tests/test_python_api.py::HumanNamePythonTests::test_utf8 # Debug how a specific name string is parsed (prints HumanName repr) -python tests.py "Dr. Juan Q. Xavier de la Vega III" +python -m nameparser "Dr. Juan Q. Xavier de la Vega III" # Build docs sphinx-build -b html docs dist/docs @@ -65,6 +66,6 @@ Parse flow: Each named attribute (`title`, `first`, etc.) is a `@property` that joins its corresponding `_list`. Setters call `_set_list()` which runs the value through `parse_pieces()`, so assigning `hn.last = "de la Vega"` correctly re-parses prefix tokens. -### Tests (`tests.py`) +### Tests (`tests/`) -All tests live in a single file. `HumanNameTestBase.m()` is a custom assert helper that prints the original name string on failure. Many test classes group cases by name format type. `TEST_NAMES` is a list of name strings that gets automatically permuted into comma-separated variants as a regression check. When adding a new parsing case, add it to the relevant test class and consider adding the base form to `TEST_NAMES`. +Tests run under **pytest** and are split one file per concern (`tests/test_titles.py`, `tests/test_suffixes.py`, etc.). `tests/base.py` holds `HumanNameTestBase` — a plain (non-`unittest`) base whose `m()` helper is a custom assert that prints the original name string on failure (plus thin `assert*` shims so the moved test bodies are unchanged). `tests/conftest.py` defines an autouse fixture that runs **every test twice** — once with `empty_attribute_default = ''` and once with `None` — so reported counts are doubled (e.g. 11 methods → 22 results); it also snapshots/restores the scalar `CONSTANTS` config around each test to keep tests order-independent. `TEST_NAMES` (in `tests/test_variations.py`) is a list of name strings permuted into comma-separated variants as a regression check. Tests that should fail use `@pytest.mark.xfail`. When adding a parsing case, add it to the relevant `tests/test_*.py` file and consider adding the base form to `TEST_NAMES`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 90898ec..9615eb5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,11 +11,16 @@ Install dev dependencies: Running Tests --------------- - python tests.py + pytest -You can also pass a name string to `tests.py` to see how it will be parsed: +Run a single test file or test: - $ python tests.py "Secretary of State Hillary Rodham-Clinton" + pytest tests/test_titles.py + pytest tests/test_titles.py::TitleTestCase + +You can also pass a name string to see how it will be parsed: + + $ python -m nameparser "Secretary of State Hillary Rodham-Clinton" **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Split the single 97KB `tests.py` into a `tests/` package (one file per concern) and run it under pytest, preserving every existing test and the dual-run-under-two-configs behavior. + +**Architecture:** Each existing `unittest`-style test class moves verbatim into its own `tests/test_*.py` file. The shared base class becomes a *plain* class (not `unittest.TestCase`) carrying the custom `m()` assert plus thin `assert*` shims, so test bodies move unchanged AND pytest's parametrized fixtures apply (they do not apply to `unittest.TestCase` subclasses). A single autouse parametrized fixture in `conftest.py` reproduces the original `__main__` block that ran the whole suite twice — once with `empty_attribute_default = ''` and once with `None`. + +**Tech Stack:** Python 3.10+, pytest, uv, ruff (with `ANN` + `UP` rule sets enabled), mypy (checks `nameparser` package only — not tests). + +--- + +## Background & Key Decisions (read before starting) + +The source today is a single file `tests.py` (344 test methods across 13 classes that subclass `HumanNameTestBase(unittest.TestCase, Generic[T])`). The `__main__` block runs `unittest.main()` twice; the second run sets `CONSTANTS.empty_attribute_default = None` globally. + +**Decisions baked into this plan:** + +1. **Base class becomes a plain class.** pytest cannot apply *parametrized* fixtures to `unittest.TestCase` subclasses. Since the dual-run is implemented as a parametrized autouse fixture, the base must be a plain class. The base provides `m()` plus `assertEqual/assertTrue/assertFalse/assertIn` shims so the ~78 `self.assert*` call sites move unchanged. +2. **`assertRaises` is NOT shimmed.** It is used only 4 times, all as `with self.assertRaises(TypeError):` in the Python-API tests, and its context-manager return type is awkward to annotate under the `ANN` ruleset. Those 4 sites are converted directly to `with pytest.raises(TypeError):`. +3. **`@unittest.skipUnless(dill, ...)` → `@pytest.mark.skipif(not dill, ...)`.** Two pickling tests use this; `unittest` skip decorators only work on `TestCase` subclasses. +4. **Dual-run = autouse parametrized fixture** over `['', None]`, restoring the prior value after each test. This doubles the run count (344 → 688), exactly matching today's two-pass behavior, and additionally isolates the global-state mutation that currently leaks between the two passes. +5. **Class names are kept** (e.g. `HumanNamePythonTests`, `TitleTestCase`), so `pytest` is configured with `python_classes = ["*Tests", "*TestCase"]`. The one oddball, `ConstantsCustomization`, is renamed to `ConstantsCustomizationTests` for consistency. +6. **The debug CLI moves to `nameparser/__main__.py`** so `python -m nameparser "Some Name"` replaces the old `python tests.py "Some Name"`. (User decision.) +7. **`tests/` is a real package** (`tests/__init__.py` present) so test modules import the base via `from tests.base import HumanNameTestBase`. +8. **`@unittest.expectedFailure` → `@pytest.mark.xfail`.** This decorator only works on `TestCase` subclasses; the plain-class equivalent is `@pytest.mark.xfail`. It appears on **10 methods** spread across 5 classes (see the "xfail" column in the table). Any file containing one of these needs `import pytest` in its header, and its reported count splits into `passed` + `xfailed` (both are success states — only `failed`/`error` are bad). The 4 `skipUnless` → `skipif` conversions in Task 2 are the analogous case for skips. + +**Source-of-truth line ranges in the current `tests.py`** (for the verbatim moves): + +| Class | Lines | Methods | Expected pytest count (×2) | Extra imports beyond base + HumanName | +|---|---|---|---|---| +| `HumanNamePythonTests` | 54–266 | 31 | 62 | `re`, `pytest`, `dill` (try/except), `Constants`, `TupleManager` | +| `FirstNameHandlingTests` | 267–330 | 11 | 18 passed, 4 xfailed | `pytest` (2 xfail) | +| `HumanNameBruteForceTests` | 331–1135 | 117 | 234 passed | — | +| `HumanNameConjunctionTestCase` | 1136–1333 | 32 | 60 passed, 4 xfailed | `pytest` (2 xfail) | +| `ConstantsCustomization` → `ConstantsCustomizationTests` | 1334–1435 | 11 | 22 passed | `Constants` (NOT top-level `CONSTANTS` — re-imported locally) | +| `NicknameTestCase` | 1436–1608 | 18 | 34 passed, 2 xfailed | `pytest` (1 xfail) | +| `PrefixesTestCase` | 1609–1723 | 18 | 36 passed | — | +| `SuffixesTestCase` | 1724–1856 | 21 | 40 passed, 2 xfailed | `pytest` (1 xfail) | +| `TitleTestCase` | 1857–2091 | 37 | 68 passed, 6 xfailed | `pytest` (3 xfail) | +| `HumanNameCapitalizationTestCase` | 2092–2170 | 14 | 26 passed, 2 xfailed | `pytest` (1 xfail) | +| `HumanNameOutputFormatTests` | 2171–2293 | 15 | 30 passed | — (Constants/CONSTANTS imported locally in methods) | +| `InitialsTestCase` | 2294–2401 | 18 | 36 passed | — (CONSTANTS imported locally in methods) | +| `TEST_NAMES` tuple | 2402–2578 | — | — | (data; lives in `test_variations.py`) | +| `HumanNameVariationTests` | 2581–2608 | 1 | 2 passed | — (uses `TEST_NAMES` from same file) | +| **TOTAL** | | **344** | **668 passed, 20 xfailed** (688 collected) | | + +**`@unittest.expectedFailure` handling (applies to the move tasks below):** any class whose row shows an xfail count contains that many `@unittest.expectedFailure` decorators. In the moved file, (a) add `import pytest` to the header, and (b) replace each `@unittest.expectedFailure` line with `@pytest.mark.xfail`. Leave the decorated method body unchanged. These convert `unittest`'s expected-failure marker (which only works on `TestCase`) into pytest's equivalent. + +`CONSTANTS` / `Constants` / `TupleManager` are imported from `nameparser.config`. `HumanName` from `nameparser`. + +**Note on `m()`:** keep its `try/except UnicodeDecodeError` fallback and its awareness of `hn.C.empty_attribute_default` exactly as in the original. + +--- + +## Task 1: Scaffold the pytest package and prove the harness + +This task creates the package, the plain base class, the dual-run fixture, the pytest config, adds the pytest dependency, and moves the **simplest** class (`FirstNameHandlingTests`) to validate the whole harness end-to-end before the mechanical moves. + +**Files:** +- Create: `tests/__init__.py` +- Create: `tests/base.py` +- Create: `tests/conftest.py` +- Create: `tests/test_first_name.py` +- Modify: `pyproject.toml` (add `pytest` to dev group; add `[tool.pytest.ini_options]`) + +- [ ] **Step 1: Create the package marker** + +Create `tests/__init__.py` as an empty file. + +- [ ] **Step 2: Create the plain base class** + +Create `tests/base.py`: + +```python +from typing import Generic, TypeVar + +from nameparser import HumanName + +T = TypeVar('T') + + +class HumanNameTestBase(Generic[T]): + """Shared assert helpers for the parsing tests. + + Formerly subclassed unittest.TestCase. It is now a plain class so pytest can + apply the parametrized dual-run fixture in conftest.py — parametrized + fixtures do not apply to unittest.TestCase subclasses. The assert* methods + are thin shims so existing test bodies move over unchanged. + """ + + def m(self, actual: T, expected: T, hn: HumanName) -> None: + """assertEqual with a better message and awareness of hn.C.empty_attribute_default""" + expected_ = expected or hn.C.empty_attribute_default + try: + assert actual == expected_, "'%s' != '%s' for '%s'\n%r" % ( + actual, + expected, + hn.original, + hn, + ) + except UnicodeDecodeError: + assert actual == expected_ + + def assertEqual(self, first: object, second: object, msg: object = None) -> None: + assert first == second, msg + + def assertTrue(self, expr: object, msg: object = None) -> None: + assert expr, msg + + def assertFalse(self, expr: object, msg: object = None) -> None: + assert not expr, msg + + def assertIn(self, member: object, container: object, msg: object = None) -> None: + assert member in container, msg # type: ignore[operator] +``` + +- [ ] **Step 3: Create the dual-run fixture** + +Create `tests/conftest.py`: + +```python +from collections.abc import Iterator + +import pytest + +from nameparser.config import CONSTANTS + + +@pytest.fixture(autouse=True, params=['', None], ids=['default', 'none']) +def empty_attribute_default(request: pytest.FixtureRequest) -> Iterator[str | None]: + """Run every test under both empty_attribute_default settings. + + Reproduces the original tests.py __main__ block, which ran the whole suite + twice — once with the default ('') and once with None — as a regression + check that the three parsing code paths agree. Restoring after each test + also isolates the global-state mutation that previously leaked between runs. + """ + original = CONSTANTS.empty_attribute_default + CONSTANTS.empty_attribute_default = request.param + yield request.param + CONSTANTS.empty_attribute_default = original +``` + +- [ ] **Step 4: Move `FirstNameHandlingTests` into its own file** + +Create `tests/test_first_name.py` with this header, then paste the **body** of `FirstNameHandlingTests` (the class line and everything indented under it, lines 267–330 of `tests.py`) verbatim. This class has **two** `@unittest.expectedFailure` decorators (lines 280, 323) — replace each with `@pytest.mark.xfail` (leave the method bodies unchanged): + +```python +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 267-330 of tests.py here, starting at: +# class FirstNameHandlingTests(HumanNameTestBase): +# ...and change the two `@unittest.expectedFailure` lines to `@pytest.mark.xfail` +``` + +- [ ] **Step 5: Add pytest dependency and config to `pyproject.toml`** + +In the `[dependency-groups]` `dev` list, add `"pytest (>=8)"`: + +```toml +[dependency-groups] +dev = [ + "pytest (>=8)", + "dill (>=0.2.5)", + "sphinx (>=8)", + "mypy (>=2.1)", + "ruff (>=0.15)" +] +``` + +Add a new section (place it after `[tool.mypy]`/before or after `[tool.ruff.lint]` — anywhere top-level is fine): + +```toml +[tool.pytest.ini_options] +testpaths = ["tests"] +python_classes = ["*Tests", "*TestCase"] +``` + +- [ ] **Step 6: Sync deps and run the new file** + +Run: `uv sync` +Then: `uv run pytest tests/test_first_name.py -q` +Expected: `18 passed, 4 xfailed` (9 passing methods × 2, plus 2 xfail methods × 2). Zero failures. Test ids look like `test_first_name[default]` and `test_first_name[none]`. + +- [ ] **Step 7: Confirm ruff is clean on the new files** + +Run: `uv run ruff check tests/` +Expected: no errors. (If `ANN` complains about the `assertIn` operator on `object`, the `# type: ignore` is for mypy only; ruff should pass. Fix any genuine annotation gaps ruff reports.) + +- [ ] **Step 8: Commit** + +```bash +git add tests/__init__.py tests/base.py tests/conftest.py tests/test_first_name.py pyproject.toml uv.lock +git commit -m "test: scaffold pytest package with dual-run fixture and first module" +``` + +--- + +## Task 2: Move `HumanNamePythonTests` (the conversion-heavy one) + +This is the only class needing real edits beyond a move: `re` import, `dill` skip decorators, and `assertRaises` → `pytest.raises`. + +**Files:** +- Create: `tests/test_python_api.py` + +- [ ] **Step 1: Create the file with the full header** + +Create `tests/test_python_api.py`: + +```python +import re + +import pytest + +try: + import dill +except ImportError: + dill = False # type: ignore[assignment] + +from nameparser import HumanName +from nameparser.config import Constants, TupleManager + +from tests.base import HumanNameTestBase + + +# <-- paste lines 54-266 of tests.py here, starting at: +# class HumanNamePythonTests(HumanNameTestBase): +``` + +- [ ] **Step 2: Convert the two pickling skip decorators** + +In the pasted body, replace both occurrences of: + +```python + @unittest.skipUnless(dill, "requires python-dill module to test pickling") +``` + +with: + +```python + @pytest.mark.skipif(not dill, reason="requires python-dill module to test pickling") +``` + +- [ ] **Step 3: Convert the four `assertRaises` context managers** + +In the pasted body, replace all four occurrences of: + +```python + with self.assertRaises(TypeError): +``` + +with: + +```python + with pytest.raises(TypeError): +``` + +- [ ] **Step 4: Verify no stray `unittest` references remain** + +Run: `grep -n "unittest" tests/test_python_api.py` +Expected: no output. (If anything prints, convert it before proceeding.) + +- [ ] **Step 5: Run the file** + +Run: `uv run pytest tests/test_python_api.py -q` +Expected: `62 passed` (31 × 2). The two pickling tests are skipped if `dill` is absent — with dill installed (it is in the dev group) they run, so expect `62 passed`. If dill is somehow missing: `58 passed, 4 skipped`. + +- [ ] **Step 6: Lint and commit** + +```bash +uv run ruff check tests/test_python_api.py +git add tests/test_python_api.py +git commit -m "test: move HumanNamePythonTests to tests/test_python_api.py" +``` + +--- + +## Task 3: Move `HumanNameBruteForceTests` + +**Files:** +- Create: `tests/test_brute_force.py` + +- [ ] **Step 1: Create the file** + +Create `tests/test_brute_force.py`: + +```python +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 331-1135 of tests.py here, starting at: +# class HumanNameBruteForceTests(HumanNameTestBase): +``` + +- [ ] **Step 2: Run the file** + +Run: `uv run pytest tests/test_brute_force.py -q` +Expected: `234 passed` (117 × 2). + +- [ ] **Step 3: Lint and commit** + +```bash +uv run ruff check tests/test_brute_force.py +git add tests/test_brute_force.py +git commit -m "test: move HumanNameBruteForceTests to tests/test_brute_force.py" +``` + +--- + +## Task 4: Move `HumanNameConjunctionTestCase` + +**Files:** +- Create: `tests/test_conjunctions.py` + +- [ ] **Step 1: Create the file** + +```python +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 1136-1333 of tests.py here, starting at: +# class HumanNameConjunctionTestCase(HumanNameTestBase): +# This class has TWO @unittest.expectedFailure decorators (lines 1218, 1322). +# Change each to @pytest.mark.xfail; leave the method bodies unchanged. +``` + +- [ ] **Step 2: Run** + +Run: `uv run pytest tests/test_conjunctions.py -q` +Expected: `60 passed, 4 xfailed` (30 passing × 2, 2 xfail × 2). Zero failures. + +- [ ] **Step 3: Lint and commit** + +```bash +uv run ruff check tests/test_conjunctions.py +git add tests/test_conjunctions.py +git commit -m "test: move HumanNameConjunctionTestCase to tests/test_conjunctions.py" +``` + +--- + +## Task 5: Move `ConstantsCustomization` (with rename) + +**Files:** +- Create: `tests/test_constants.py` + +- [ ] **Step 1: Create the file** + +```python +from nameparser import HumanName +from nameparser.config import CONSTANTS, Constants + +from tests.base import HumanNameTestBase + + +# <-- paste lines 1334-1435 of tests.py here, starting at: +# class ConstantsCustomization(HumanNameTestBase): +``` + +- [ ] **Step 2: Rename the class for collection consistency** + +Change the pasted class line from: + +```python +class ConstantsCustomization(HumanNameTestBase): +``` + +to: + +```python +class ConstantsCustomizationTests(HumanNameTestBase): +``` + +- [ ] **Step 3: Run** + +Run: `uv run pytest tests/test_constants.py -q` +Expected: `22 passed` (11 × 2). Note: drop `CONSTANTS` from the top-level import — `test_empty_attribute_default` re-imports it locally, so a top-level import is redundant (ruff F811). + +- [ ] **Step 4: Lint and commit** + +```bash +uv run ruff check tests/test_constants.py +git add tests/test_constants.py +git commit -m "test: move ConstantsCustomization to tests/test_constants.py and rename for pytest collection" +``` + +--- + +## Task 6: Move `NicknameTestCase` + +**Files:** +- Create: `tests/test_nicknames.py` + +- [ ] **Step 1: Create the file** + +```python +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 1436-1608 of tests.py here, starting at: +# class NicknameTestCase(HumanNameTestBase): +# This class has ONE @unittest.expectedFailure decorator (line 1557). +# Change it to @pytest.mark.xfail; leave the method body unchanged. +``` + +- [ ] **Step 2: Run** + +Run: `uv run pytest tests/test_nicknames.py -q` +Expected: `34 passed, 2 xfailed` (17 passing × 2, 1 xfail × 2). Zero failures. + +- [ ] **Step 3: Lint and commit** + +```bash +uv run ruff check tests/test_nicknames.py +git add tests/test_nicknames.py +git commit -m "test: move NicknameTestCase to tests/test_nicknames.py" +``` + +--- + +## Task 7: Move `PrefixesTestCase` + +**Files:** +- Create: `tests/test_prefixes.py` + +- [ ] **Step 1: Create the file** + +```python +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 1609-1723 of tests.py here, starting at: +# class PrefixesTestCase(HumanNameTestBase): +``` + +- [ ] **Step 2: Run** + +Run: `uv run pytest tests/test_prefixes.py -q` +Expected: `36 passed` (18 × 2). + +- [ ] **Step 3: Lint and commit** + +```bash +uv run ruff check tests/test_prefixes.py +git add tests/test_prefixes.py +git commit -m "test: move PrefixesTestCase to tests/test_prefixes.py" +``` + +--- + +## Task 8: Move `SuffixesTestCase` + +**Files:** +- Create: `tests/test_suffixes.py` + +- [ ] **Step 1: Create the file** + +```python +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 1724-1856 of tests.py here, starting at: +# class SuffixesTestCase(HumanNameTestBase): +# This class has ONE @unittest.expectedFailure decorator (line 1831). +# Change it to @pytest.mark.xfail; leave the method body unchanged. +``` + +- [ ] **Step 2: Run** + +Run: `uv run pytest tests/test_suffixes.py -q` +Expected: `40 passed, 2 xfailed` (20 passing × 2, 1 xfail × 2). Zero failures. + +- [ ] **Step 3: Lint and commit** + +```bash +uv run ruff check tests/test_suffixes.py +git add tests/test_suffixes.py +git commit -m "test: move SuffixesTestCase to tests/test_suffixes.py" +``` + +--- + +## Task 9: Move `TitleTestCase` + +**Files:** +- Create: `tests/test_titles.py` + +- [ ] **Step 1: Create the file** + +```python +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 1857-2091 of tests.py here, starting at: +# class TitleTestCase(HumanNameTestBase): +# This class has THREE @unittest.expectedFailure decorators (lines 1903, 1939, 2030). +# Change each to @pytest.mark.xfail; leave the method bodies unchanged. +``` + +- [ ] **Step 2: Run** + +Run: `uv run pytest tests/test_titles.py -q` +Expected: `68 passed, 6 xfailed` (34 passing × 2, 3 xfail × 2). Zero failures. + +- [ ] **Step 3: Lint and commit** + +```bash +uv run ruff check tests/test_titles.py +git add tests/test_titles.py +git commit -m "test: move TitleTestCase to tests/test_titles.py" +``` + +--- + +## Task 10: Move `HumanNameCapitalizationTestCase` + +**Files:** +- Create: `tests/test_capitalization.py` + +- [ ] **Step 1: Create the file** + +```python +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 2092-2170 of tests.py here, starting at: +# class HumanNameCapitalizationTestCase(HumanNameTestBase): +# This class has ONE @unittest.expectedFailure decorator (line 2100). +# Change it to @pytest.mark.xfail; leave the method body unchanged. +``` + +- [ ] **Step 2: Run** + +Run: `uv run pytest tests/test_capitalization.py -q` +Expected: `26 passed, 2 xfailed` (13 passing × 2, 1 xfail × 2). Zero failures. + +- [ ] **Step 3: Lint and commit** + +```bash +uv run ruff check tests/test_capitalization.py +git add tests/test_capitalization.py +git commit -m "test: move HumanNameCapitalizationTestCase to tests/test_capitalization.py" +``` + +--- + +## Task 11: Move `HumanNameOutputFormatTests` + +**Files:** +- Create: `tests/test_output_format.py` + +- [ ] **Step 1: Create the file** + +```python +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 2171-2293 of tests.py here, starting at: +# class HumanNameOutputFormatTests(HumanNameTestBase): +# NOTE: this class imports Constants/CONSTANTS LOCALLY inside its test methods, +# so do NOT add a top-level nameparser.config import (it would be redundant — ruff F811). +``` + +- [ ] **Step 2: Run** + +Run: `uv run pytest tests/test_output_format.py -q` +Expected: `30 passed` (15 × 2). + +- [ ] **Step 3: Lint and commit** + +```bash +uv run ruff check tests/test_output_format.py +git add tests/test_output_format.py +git commit -m "test: move HumanNameOutputFormatTests to tests/test_output_format.py" +``` + +--- + +## Task 12: Move `InitialsTestCase` + +Note: only the class moves here — the `TEST_NAMES` tuple that follows it (lines 2402–2578) belongs to Task 13. Paste **only** lines 2294–2401. + +**Files:** +- Create: `tests/test_initials.py` + +- [ ] **Step 1: Create the file** + +```python +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 2294-2401 of tests.py here, starting at: +# class InitialsTestCase(HumanNameTestBase): +# Stop BEFORE the `TEST_NAMES = (` line at 2402. +# NOTE: this class imports CONSTANTS LOCALLY inside its test methods, +# so do NOT add a top-level nameparser.config import (ruff F811). +``` + +- [ ] **Step 2: Run** + +Run: `uv run pytest tests/test_initials.py -q` +Expected: `36 passed` (18 × 2). + +- [ ] **Step 3: Lint and commit** + +```bash +uv run ruff check tests/test_initials.py +git add tests/test_initials.py +git commit -m "test: move InitialsTestCase to tests/test_initials.py" +``` + +--- + +## Task 13: Move `TEST_NAMES` + `HumanNameVariationTests` + +The `TEST_NAMES` tuple (lines 2402–2578) and the class that consumes it move together into one file. + +**Files:** +- Create: `tests/test_variations.py` + +- [ ] **Step 1: Create the file** + +Paste the `TEST_NAMES = ( ... )` tuple (lines 2402–2578) first, then the `HumanNameVariationTests` class (lines 2581–2608), under this header: + +```python +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +# <-- paste lines 2402-2578 (the TEST_NAMES tuple) here, then a blank line, then +# paste lines 2581-2608, starting at: +# class HumanNameVariationTests(HumanNameTestBase): +``` + +The class keeps its `TEST_NAMES = TEST_NAMES` line verbatim (it aliases the module-level tuple onto the class). + +- [ ] **Step 2: Run** + +Run: `uv run pytest tests/test_variations.py -q` +Expected: `2 passed` (1 method × 2). + +- [ ] **Step 3: Lint and commit** + +```bash +uv run ruff check tests/test_variations.py +git add tests/test_variations.py +git commit -m "test: move TEST_NAMES and HumanNameVariationTests to tests/test_variations.py" +``` + +--- + +## Task 14: Move the debug CLI to `nameparser/__main__.py`, delete `tests.py` + +**Files:** +- Create: `nameparser/__main__.py` +- Delete: `tests.py` + +- [ ] **Step 1: Create `nameparser/__main__.py`** + +This replicates the old `python tests.py "name"` debug path as `python -m nameparser "name"`: + +```python +"""Command-line debug helper: parse a name and print the result. + +Usage: + + python -m nameparser "Dr. Juan Q. Xavier de la Vega III" +""" +import logging +import sys + +from nameparser import HumanName + + +def main() -> None: + if len(sys.argv) <= 1: + print('Usage: python -m nameparser "Name String"') + raise SystemExit(1) + log = logging.getLogger('HumanName') + log.setLevel(logging.ERROR) + log.addHandler(logging.StreamHandler()) + name_string = sys.argv[1] + hn = HumanName(name_string, encoding=sys.stdout.encoding) + print(repr(hn)) + hn.capitalize() + print(repr(hn)) + print("Initials: " + hn.initials()) + + +if __name__ == '__main__': + main() +``` + +- [ ] **Step 2: Verify the CLI works** + +Run: `uv run python -m nameparser "Dr. Juan Q. Xavier de la Vega III"` +Expected: a `` repr printed twice (raw, then capitalized) followed by an `Initials:` line. + +- [ ] **Step 3: Delete the old test file** + +Run: `git rm tests.py` + +- [ ] **Step 4: Run the entire suite** + +Run: `uv run pytest -q` +Expected: `668 passed, 20 xfailed` (334 passing methods × 2, plus 10 `xfail` methods × 2 = 688 collected). Zero failures, zero errors. With dill present (dev group), no skips. + +- [ ] **Step 5: Run ruff and mypy across the repo** + +Run: `uv run ruff check` +Run: `uv run mypy` +Expected: both clean. (mypy is configured to check only `nameparser`, so the new `__main__.py` is type-checked but the tests are not.) + +- [ ] **Step 6: Commit** + +```bash +git add nameparser/__main__.py +git rm tests.py +git commit -m "feat: add 'python -m nameparser' debug CLI; remove monolithic tests.py" +``` + +--- + +## Task 15: Update docs and CI to use pytest + +**Files:** +- Modify: `.github/workflows/python-package.yml` (line ~43) +- Modify: `CONTRIBUTING.md` (Running Tests section) +- Modify: `AGENTS.md` (test commands + Tests section) + +- [ ] **Step 1: Update CI** + +In `.github/workflows/python-package.yml`, under the `Run Tests` step, replace: + +```yaml + python tests.py +``` + +with: + +```yaml + pytest +``` + +(The `--group dev` install already brings in pytest.) + +- [ ] **Step 2: Update `CONTRIBUTING.md`** + +Replace the `Running Tests` block: + +``` +Running Tests +--------------- + + python tests.py + +You can also pass a name string to `tests.py` to see how it will be parsed: + + $ python tests.py "Secretary of State Hillary Rodham-Clinton" +``` + +with: + +``` +Running Tests +--------------- + + pytest + +Run a single test file or test: + + pytest tests/test_titles.py + pytest tests/test_titles.py -k test_two_part_title + +You can also pass a name string to see how it will be parsed: + + $ python -m nameparser "Secretary of State Hillary Rodham-Clinton" +``` + +Leave the surrounding example output and the `Writing Tests` paragraph about `TEST_NAMES` intact (the `TEST_NAMES` tuple still exists, now in `tests/test_variations.py`). + +- [ ] **Step 3: Update `AGENTS.md`** + +Replace the test-command block: + +``` +# Run all tests +python tests.py + +# Run a single test by class/method +python -m unittest tests.HumanNamePythonTests.test_utf8 + +# ... +python tests.py "Dr. Juan Q. Xavier de la Vega III" +``` + +with: + +``` +# Run all tests +pytest + +# Run a single test file / class / method +pytest tests/test_python_api.py +pytest tests/test_python_api.py::HumanNamePythonTests::test_utf8 + +# Parse a name string to see how it parses +python -m nameparser "Dr. Juan Q. Xavier de la Vega III" +``` + +Then update the `### Tests (tests.py)` section: rename it to `### Tests (tests/)` and rewrite its body to describe the new layout — one file per concern under `tests/`, the plain `HumanNameTestBase.m()` helper in `tests/base.py`, the autouse `empty_attribute_default` fixture in `tests/conftest.py` that runs every test under both `''` and `None` (so reported counts are doubled), and that `TEST_NAMES` now lives in `tests/test_variations.py`. + +- [ ] **Step 4: Sanity-check the doc commands** + +Run: `uv run pytest tests/test_python_api.py::HumanNamePythonTests::test_utf8 -q` +Expected: `2 passed` (the dual-run params). + +- [ ] **Step 5: Commit** + +```bash +git add .github/workflows/python-package.yml CONTRIBUTING.md AGENTS.md +git commit -m "docs: update test instructions and CI for pytest" +``` + +--- + +## Final verification (after all tasks) + +- [ ] `uv run pytest -q` → `668 passed, 20 xfailed` (688 collected, zero failures) +- [ ] `uv run ruff check` → clean +- [ ] `uv run mypy` → clean +- [ ] `uv run python -m nameparser "Dr. Juan Q. Xavier de la Vega III"` → prints parsed repr +- [ ] `git status` shows `tests.py` deleted and `tests/` + `nameparser/__main__.py` added +- [ ] No file in `tests/` contains the string `unittest`: `grep -rn unittest tests/` → no output +``` diff --git a/nameparser/__main__.py b/nameparser/__main__.py new file mode 100644 index 0000000..91978ec --- /dev/null +++ b/nameparser/__main__.py @@ -0,0 +1,29 @@ +"""Command-line debug helper: parse a name and print the result. + +Usage: + + python -m nameparser "Dr. Juan Q. Xavier de la Vega III" +""" +import logging +import sys + +from nameparser import HumanName + + +def main() -> None: + if len(sys.argv) <= 1: + print('Usage: python -m nameparser "Name String"') + raise SystemExit(1) + log = logging.getLogger('HumanName') + log.setLevel(logging.ERROR) + log.addHandler(logging.StreamHandler()) + name_string = sys.argv[1] + hn = HumanName(name_string, encoding=sys.stdout.encoding) + print(repr(hn)) + hn.capitalize() + print(repr(hn)) + print("Initials: " + hn.initials()) + + +if __name__ == '__main__': + main() diff --git a/nameparser/parser.py b/nameparser/parser.py index ee361de..9edc905 100644 --- a/nameparser/parser.py +++ b/nameparser/parser.py @@ -273,17 +273,21 @@ def initials(self) -> str: middle_initials_list = [self.__process_initial__(name) for name in self.middle_list if name] last_initials_list = [self.__process_initial__(name) for name in self.last_list if name] + # Empty parts must render as '' (not empty_attribute_default, which may be + # None) so str.format does not interpolate the literal "None" into the + # output. A fully-empty result falls back to empty_attribute_default, + # matching the other attribute accessors (e.g. ``first``). initials_dict = { "first": (self.initials_delimiter + " ").join(first_initials_list) + self.initials_delimiter - if len(first_initials_list) else self.C.empty_attribute_default, + if len(first_initials_list) else "", "middle": (self.initials_delimiter + " ").join(middle_initials_list) + self.initials_delimiter - if len(middle_initials_list) else self.C.empty_attribute_default, + if len(middle_initials_list) else "", "last": (self.initials_delimiter + " ").join(last_initials_list) + self.initials_delimiter - if len(last_initials_list) else self.C.empty_attribute_default + if len(last_initials_list) else "" } _s = self.initials_format.format(**initials_dict) - return self.collapse_whitespace(_s) + return self.collapse_whitespace(_s) or self.C.empty_attribute_default @property def has_own_config(self) -> bool: diff --git a/pyproject.toml b/pyproject.toml index cba07ff..a1130ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ nameparser = ["py.typed"] [dependency-groups] dev = [ + "pytest (>=8)", "dill (>=0.2.5)", "sphinx (>=8)", "mypy (>=2.1)", @@ -54,6 +55,10 @@ module = [ ] ignore_missing_imports = true +[tool.pytest.ini_options] +testpaths = ["tests"] +python_classes = ["*Tests", "*TestCase"] + [tool.ruff.lint] extend-select = [ "ANN", # flake8-annotations diff --git a/tests.py b/tests.py deleted file mode 100644 index c137ab4..0000000 --- a/tests.py +++ /dev/null @@ -1,2630 +0,0 @@ -# ruff: noqa: E402 -import unittest -""" -Run this file to run the tests. - -``python tests.py`` - -Or install nose and run nosetests. - -``pip install nose`` - -then: - -``nosetests`` - -Post a ticket and/or clone and fix it. Pull requests with tests gladly accepted. -https://github.com/derek73/python-nameparser/issues -https://github.com/derek73/python-nameparser/pulls -""" - -import logging -import re -from typing import Generic, TypeVar - -try: - import dill -except ImportError: - dill = False - -from nameparser import HumanName -from nameparser.config import Constants, TupleManager - -log = logging.getLogger('HumanName') - - -T = TypeVar('T') - - -class HumanNameTestBase(unittest.TestCase, Generic[T]): - def m(self, actual: T, expected: T, hn: HumanName) -> None: - """assertEqual with a better message and awareness of hn.C.empty_attribute_default""" - expected_ = expected or hn.C.empty_attribute_default - try: - self.assertEqual(actual, expected_, "'%s' != '%s' for '%s'\n%r" % ( - actual, - expected, - hn.original, - hn - )) - except UnicodeDecodeError: - self.assertEqual(actual, expected_) - - -class HumanNamePythonTests(HumanNameTestBase): - - def test_utf8(self) -> None: - hn = HumanName("de la Véña, Jüan") - self.m(hn.first, "Jüan", hn) - self.m(hn.last, "de la Véña", hn) - - def test_string_output(self) -> None: - hn = HumanName("de la Véña, Jüan") - self.m(str(hn), "Jüan de la Véña", hn) - - def test_escaped_utf8_bytes(self) -> None: - hn = HumanName(b'B\xc3\xb6ck, Gerald') - self.m(hn.first, "Gerald", hn) - self.m(hn.last, "Böck", hn) - - def test_len(self) -> None: - hn = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") - self.m(len(hn), 5, hn) - hn = HumanName("John Doe") - self.m(len(hn), 2, hn) - - @unittest.skipUnless(dill, "requires python-dill module to test pickling") - def test_config_pickle(self) -> None: - constants = Constants() - self.assertTrue(dill.pickles(constants)) - - @unittest.skipUnless(dill, "requires python-dill module to test pickling") - def test_name_instance_pickle(self) -> None: - hn = HumanName("Title First Middle Middle Last, Jr.") - self.assertTrue(dill.pickles(hn)) - - def test_comparison(self) -> None: - hn1 = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") - hn2 = HumanName("Dr. John P. Doe-Ray, CLU, CFP, LUTC") - self.assertTrue(hn1 == hn2) - self.assertTrue(hn1 is not hn2) - self.assertTrue(hn1 == "Dr. John P. Doe-Ray CLU, CFP, LUTC") - hn1 = HumanName("Doe, Dr. John P., CLU, CFP, LUTC") - hn2 = HumanName("Dr. John P. Doe-Ray, CLU, CFP, LUTC") - self.assertTrue(not hn1 == hn2) - self.assertTrue(not hn1 == 0) - self.assertTrue(not hn1 == "test") - self.assertTrue(not hn1 == ["test"]) - self.assertTrue(not hn1 == {"test": hn2}) - - def test_assignment_to_full_name(self) -> None: - hn = HumanName("John A. Kenneth Doe, Jr.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.suffix, "Jr.", hn) - hn.full_name = "Juan Velasquez y Garcia III" - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test_get_full_name_attribute_references_internal_lists(self) -> None: - hn = HumanName("John Williams") - hn.first_list = ["Larry"] - self.m(hn.full_name, "Larry Williams", hn) - - def test_assignment_to_attribute(self) -> None: - hn = HumanName("John A. Kenneth Doe, Jr.") - hn.last = "de la Vega" - self.m(hn.last, "de la Vega", hn) - hn.title = "test" - self.m(hn.title, "test", hn) - hn.first = "test" - self.m(hn.first, "test", hn) - hn.middle = "test" - self.m(hn.middle, "test", hn) - hn.suffix = "test" - self.m(hn.suffix, "test", hn) - with self.assertRaises(TypeError): - hn.suffix = [['test']] - with self.assertRaises(TypeError): - hn.suffix = {"test": "test"} - - def test_assign_list_to_attribute(self) -> None: - hn = HumanName("John A. Kenneth Doe, Jr.") - hn.title = ["test1", "test2"] - self.m(hn.title, "test1 test2", hn) - hn.first = ["test3", "test4"] - self.m(hn.first, "test3 test4", hn) - hn.middle = ["test5", "test6", "test7"] - self.m(hn.middle, "test5 test6 test7", hn) - hn.last = ["test8", "test9", "test10"] - self.m(hn.last, "test8 test9 test10", hn) - hn.suffix = ['test'] - self.m(hn.suffix, "test", hn) - - def test_comparison_case_insensitive(self) -> None: - hn1 = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") - hn2 = HumanName("dr. john p. doe-Ray, CLU, CFP, LUTC") - self.assertTrue(hn1 == hn2) - self.assertTrue(hn1 is not hn2) - self.assertTrue(hn1 == "Dr. John P. Doe-ray clu, CFP, LUTC") - - def test_slice(self) -> None: - hn = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") - self.m(list(hn), ['Dr.', 'John', 'P.', 'Doe-Ray', 'CLU, CFP, LUTC'], hn) - self.m(hn[1:], ['John', 'P.', 'Doe-Ray', 'CLU, CFP, LUTC', hn.C.empty_attribute_default], hn) - self.m(hn[1:-2], ['John', 'P.', 'Doe-Ray'], hn) - - def test_getitem(self) -> None: - hn = HumanName("Dr. John A. Kenneth Doe, Jr.") - self.m(hn['title'], "Dr.", hn) - self.m(hn['first'], "John", hn) - self.m(hn['last'], "Doe", hn) - self.m(hn['middle'], "A. Kenneth", hn) - self.m(hn['suffix'], "Jr.", hn) - - def test_setitem(self) -> None: - hn = HumanName("Dr. John A. Kenneth Doe, Jr.") - hn['title'] = 'test' - self.m(hn['title'], "test", hn) - hn['last'] = ['test', 'test2'] - self.m(hn['last'], "test test2", hn) - with self.assertRaises(TypeError): - hn["suffix"] = [['test']] - with self.assertRaises(TypeError): - hn["suffix"] = {"test": "test"} - - def test_conjunction_names(self) -> None: - hn = HumanName("johnny y") - self.m(hn.first, "johnny", hn) - self.m(hn.last, "y", hn) - - def test_prefix_names(self) -> None: - hn = HumanName("vai la") - self.m(hn.first, "vai", hn) - self.m(hn.last, "la", hn) - - def test_blank_name(self) -> None: - hn = HumanName() - self.m(hn.first, "", hn) - self.m(hn.last, "", hn) - - def test_surnames_list_attribute(self) -> None: - hn = HumanName("John Edgar Casey Williams III") - self.m(hn.surnames_list, ["Edgar", "Casey", "Williams"], hn) - - def test_surnames_attribute(self) -> None: - hn = HumanName("John Edgar Casey Williams III") - self.m(hn.surnames, "Edgar Casey Williams", hn) - - def test_is_prefix_with_list(self) -> None: - hn = HumanName() - items = ['firstname', 'lastname', 'del'] - self.assertTrue(hn.is_prefix(items)) - self.assertTrue(hn.is_prefix(items[1:])) - - def test_is_conjunction_with_list(self) -> None: - hn = HumanName() - items = ['firstname', 'lastname', 'and'] - self.assertTrue(hn.is_conjunction(items)) - self.assertTrue(hn.is_conjunction(items[1:])) - - def test_override_constants(self) -> None: - C = Constants() - hn = HumanName(constants=C) - self.assertTrue(hn.C is C) - - def test_override_regex(self) -> None: - var = TupleManager([("spaces", re.compile(r"\s+", re.U)),]) - C = Constants(regexes=var) - hn = HumanName(constants=C) - self.assertTrue(hn.C.regexes == var) - - def test_override_titles(self) -> None: - var = ["abc","def"] - C = Constants(titles=var) - hn = HumanName(constants=C) - self.assertTrue(sorted(hn.C.titles) == sorted(var)) - - def test_override_first_name_titles(self) -> None: - var = ["abc","def"] - C = Constants(first_name_titles=var) - hn = HumanName(constants=C) - self.assertTrue(sorted(hn.C.first_name_titles) == sorted(var)) - - def test_override_prefixes(self) -> None: - var = ["abc","def"] - C = Constants(prefixes=var) - hn = HumanName(constants=C) - self.assertTrue(sorted(hn.C.prefixes) == sorted(var)) - - def test_override_suffix_acronyms(self) -> None: - var = ["abc","def"] - C = Constants(suffix_acronyms=var) - hn = HumanName(constants=C) - self.assertTrue(sorted(hn.C.suffix_acronyms) == sorted(var)) - - def test_override_suffix_not_acronyms(self) -> None: - var = ["abc","def"] - C = Constants(suffix_not_acronyms=var) - hn = HumanName(constants=C) - self.assertTrue(sorted(hn.C.suffix_not_acronyms) == sorted(var)) - - def test_override_conjunctions(self) -> None: - var = ["abc","def"] - C = Constants(conjunctions=var) - hn = HumanName(constants=C) - self.assertTrue(sorted(hn.C.conjunctions) == sorted(var)) - - def test_override_capitalization_exceptions(self) -> None: - var = TupleManager([("spaces", re.compile(r"\s+", re.U)),]) - C = Constants(capitalization_exceptions=var) - hn = HumanName(constants=C) - self.assertTrue(hn.C.capitalization_exceptions == var) - - -class FirstNameHandlingTests(HumanNameTestBase): - def test_first_name(self) -> None: - hn = HumanName("Andrew") - self.m(hn.first, "Andrew", hn) - - def test_assume_title_and_one_other_name_is_last_name(self) -> None: - hn = HumanName("Rev Andrews") - self.m(hn.title, "Rev", hn) - self.m(hn.last, "Andrews", hn) - - # TODO: Seems "Andrews, M.D.", Andrews should be treated as a last name - # but other suffixes like "George Jr." should be first names. Might be - # related to https://github.com/derek73/python-nameparser/issues/2 - @unittest.expectedFailure - def test_assume_suffix_title_and_one_other_name_is_last_name(self) -> None: - hn = HumanName("Andrews, M.D.") - self.m(hn.suffix, "M.D.", hn) - self.m(hn.last, "Andrews", hn) - - def test_suffix_in_lastname_part_of_lastname_comma_format(self) -> None: - hn = HumanName("Smith Jr., John") - self.m(hn.last, "Smith", hn) - self.m(hn.first, "John", hn) - self.m(hn.suffix, "Jr.", hn) - - def test_sir_exception_to_first_name_rule(self) -> None: - hn = HumanName("Sir Gerald") - self.m(hn.title, "Sir", hn) - self.m(hn.first, "Gerald", hn) - - def test_king_exception_to_first_name_rule(self) -> None: - hn = HumanName("King Henry") - self.m(hn.title, "King", hn) - self.m(hn.first, "Henry", hn) - - def test_queen_exception_to_first_name_rule(self) -> None: - hn = HumanName("Queen Elizabeth") - self.m(hn.title, "Queen", hn) - self.m(hn.first, "Elizabeth", hn) - - def test_dame_exception_to_first_name_rule(self) -> None: - hn = HumanName("Dame Mary") - self.m(hn.title, "Dame", hn) - self.m(hn.first, "Mary", hn) - - def test_first_name_is_not_prefix_if_only_two_parts(self) -> None: - """When there are only two parts, don't join prefixes or conjunctions""" - hn = HumanName("Van Nguyen") - self.m(hn.first, "Van", hn) - self.m(hn.last, "Nguyen", hn) - - def test_first_name_is_not_prefix_if_only_two_parts_comma(self) -> None: - hn = HumanName("Nguyen, Van") - self.m(hn.first, "Van", hn) - self.m(hn.last, "Nguyen", hn) - - @unittest.expectedFailure - def test_first_name_is_prefix_if_three_parts(self) -> None: - """Not sure how to fix this without breaking Mr and Mrs""" - hn = HumanName("Mr. Van Nguyen") - self.m(hn.first, "Van", hn) - self.m(hn.last, "Nguyen", hn) - - -class HumanNameBruteForceTests(HumanNameTestBase): - - def test1(self) -> None: - hn = HumanName("John Doe") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - - def test2(self) -> None: - hn = HumanName("John Doe, Jr.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "Jr.", hn) - - def test3(self) -> None: - hn = HumanName("John Doe III") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "III", hn) - - def test4(self) -> None: - hn = HumanName("Doe, John") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - - def test5(self) -> None: - hn = HumanName("Doe, John, Jr.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "Jr.", hn) - - def test6(self) -> None: - hn = HumanName("Doe, John III") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "III", hn) - - def test7(self) -> None: - hn = HumanName("John A. Doe") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - - def test8(self) -> None: - hn = HumanName("John A. Doe, Jr") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - self.m(hn.suffix, "Jr", hn) - - def test9(self) -> None: - hn = HumanName("John A. Doe III") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - self.m(hn.suffix, "III", hn) - - def test10(self) -> None: - hn = HumanName("Doe, John A.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - - def test11(self) -> None: - hn = HumanName("Doe, John A., Jr.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - self.m(hn.suffix, "Jr.", hn) - - def test12(self) -> None: - hn = HumanName("Doe, John A., III") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - self.m(hn.suffix, "III", hn) - - def test13(self) -> None: - hn = HumanName("John A. Kenneth Doe") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - - def test14(self) -> None: - hn = HumanName("John A. Kenneth Doe, Jr.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.suffix, "Jr.", hn) - - def test15(self) -> None: - hn = HumanName("John A. Kenneth Doe III") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.suffix, "III", hn) - - def test16(self) -> None: - hn = HumanName("Doe, John. A. Kenneth") - self.m(hn.first, "John.", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - - def test17(self) -> None: - hn = HumanName("Doe, John. A. Kenneth, Jr.") - self.m(hn.first, "John.", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.suffix, "Jr.", hn) - - def test18(self) -> None: - hn = HumanName("Doe, John. A. Kenneth III") - self.m(hn.first, "John.", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.suffix, "III", hn) - - def test19(self) -> None: - hn = HumanName("Dr. John Doe") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.title, "Dr.", hn) - - def test20(self) -> None: - hn = HumanName("Dr. John Doe, Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "Jr.", hn) - - def test21(self) -> None: - hn = HumanName("Dr. John Doe III") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "III", hn) - - def test22(self) -> None: - hn = HumanName("Doe, Dr. John") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - - def test23(self) -> None: - hn = HumanName("Doe, Dr. John, Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "Jr.", hn) - - def test24(self) -> None: - hn = HumanName("Doe, Dr. John III") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "III", hn) - - def test25(self) -> None: - hn = HumanName("Dr. John A. Doe") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - - def test26(self) -> None: - hn = HumanName("Dr. John A. Doe, Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - self.m(hn.suffix, "Jr.", hn) - - def test27(self) -> None: - hn = HumanName("Dr. John A. Doe III") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - self.m(hn.suffix, "III", hn) - - def test28(self) -> None: - hn = HumanName("Doe, Dr. John A.") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - - def test29(self) -> None: - hn = HumanName("Doe, Dr. John A. Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - self.m(hn.suffix, "Jr.", hn) - - def test30(self) -> None: - hn = HumanName("Doe, Dr. John A. III") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "A.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "III", hn) - - def test31(self) -> None: - hn = HumanName("Dr. John A. Kenneth Doe") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - - def test32(self) -> None: - hn = HumanName("Dr. John A. Kenneth Doe, Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "Jr.", hn) - - def test33(self) -> None: - hn = HumanName("Al Arnold Gore, Jr.") - self.m(hn.middle, "Arnold", hn) - self.m(hn.first, "Al", hn) - self.m(hn.last, "Gore", hn) - self.m(hn.suffix, "Jr.", hn) - - def test34(self) -> None: - hn = HumanName("Dr. John A. Kenneth Doe III") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "III", hn) - - def test35(self) -> None: - hn = HumanName("Doe, Dr. John A. Kenneth") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - - def test36(self) -> None: - hn = HumanName("Doe, Dr. John A. Kenneth Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "Jr.", hn) - - def test37(self) -> None: - hn = HumanName("Doe, Dr. John A. Kenneth III") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "III", hn) - - def test38(self) -> None: - hn = HumanName("Juan de la Vega") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - - def test39(self) -> None: - hn = HumanName("Juan de la Vega, Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.suffix, "Jr.", hn) - - def test40(self) -> None: - hn = HumanName("Juan de la Vega III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.suffix, "III", hn) - - def test41(self) -> None: - hn = HumanName("de la Vega, Juan") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - - def test42(self) -> None: - hn = HumanName("de la Vega, Juan, Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.suffix, "Jr.", hn) - - def test43(self) -> None: - hn = HumanName("de la Vega, Juan III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.suffix, "III", hn) - - def test44(self) -> None: - hn = HumanName("Juan Velasquez y Garcia") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test45(self) -> None: - hn = HumanName("Juan Velasquez y Garcia, Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test46(self) -> None: - hn = HumanName("Juan Velasquez y Garcia III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test47(self) -> None: - hn = HumanName("Velasquez y Garcia, Juan") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test48(self) -> None: - hn = HumanName("Velasquez y Garcia, Juan, Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test49(self) -> None: - hn = HumanName("Velasquez y Garcia, Juan III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test50(self) -> None: - hn = HumanName("Dr. Juan de la Vega") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - - def test51(self) -> None: - hn = HumanName("Dr. Juan de la Vega, Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.suffix, "Jr.", hn) - - def test52(self) -> None: - hn = HumanName("Dr. Juan de la Vega III") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.suffix, "III", hn) - - def test53(self) -> None: - hn = HumanName("de la Vega, Dr. Juan") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - - def test54(self) -> None: - hn = HumanName("de la Vega, Dr. Juan, Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.suffix, "Jr.", hn) - - def test55(self) -> None: - hn = HumanName("de la Vega, Dr. Juan III") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.suffix, "III", hn) - - def test56(self) -> None: - hn = HumanName("Dr. Juan Velasquez y Garcia") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test57(self) -> None: - hn = HumanName("Dr. Juan Velasquez y Garcia, Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test58(self) -> None: - hn = HumanName("Dr. Juan Velasquez y Garcia III") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test59(self) -> None: - hn = HumanName("Velasquez y Garcia, Dr. Juan") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test60(self) -> None: - hn = HumanName("Velasquez y Garcia, Dr. Juan, Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test61(self) -> None: - hn = HumanName("Velasquez y Garcia, Dr. Juan III") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test62(self) -> None: - hn = HumanName("Juan Q. de la Vega") - self.m(hn.first, "Juan", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.last, "de la Vega", hn) - - def test63(self) -> None: - hn = HumanName("Juan Q. de la Vega, Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.suffix, "Jr.", hn) - - def test64(self) -> None: - hn = HumanName("Juan Q. de la Vega III") - self.m(hn.first, "Juan", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.suffix, "III", hn) - - def test65(self) -> None: - hn = HumanName("de la Vega, Juan Q.") - self.m(hn.first, "Juan", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.last, "de la Vega", hn) - - def test66(self) -> None: - hn = HumanName("de la Vega, Juan Q., Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.suffix, "Jr.", hn) - - def test67(self) -> None: - hn = HumanName("de la Vega, Juan Q. III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.suffix, "III", hn) - - def test68(self) -> None: - hn = HumanName("Juan Q. Velasquez y Garcia") - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test69(self) -> None: - hn = HumanName("Juan Q. Velasquez y Garcia, Jr.") - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test70(self) -> None: - hn = HumanName("Juan Q. Velasquez y Garcia III") - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test71(self) -> None: - hn = HumanName("Velasquez y Garcia, Juan Q.") - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test72(self) -> None: - hn = HumanName("Velasquez y Garcia, Juan Q., Jr.") - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test73(self) -> None: - hn = HumanName("Velasquez y Garcia, Juan Q. III") - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test74(self) -> None: - hn = HumanName("Dr. Juan Q. de la Vega") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.last, "de la Vega", hn) - - def test75(self) -> None: - hn = HumanName("Dr. Juan Q. de la Vega, Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.suffix, "Jr.", hn) - - def test76(self) -> None: - hn = HumanName("Dr. Juan Q. de la Vega III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.suffix, "III", hn) - - def test77(self) -> None: - hn = HumanName("de la Vega, Dr. Juan Q.") - self.m(hn.first, "Juan", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.title, "Dr.", hn) - - def test78(self) -> None: - hn = HumanName("de la Vega, Dr. Juan Q., Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.suffix, "Jr.", hn) - self.m(hn.title, "Dr.", hn) - - def test79(self) -> None: - hn = HumanName("de la Vega, Dr. Juan Q. III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.suffix, "III", hn) - self.m(hn.title, "Dr.", hn) - - def test80(self) -> None: - hn = HumanName("Dr. Juan Q. Velasquez y Garcia") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test81(self) -> None: - hn = HumanName("Dr. Juan Q. Velasquez y Garcia, Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test82(self) -> None: - hn = HumanName("Dr. Juan Q. Velasquez y Garcia III") - self.m(hn.middle, "Q.", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test83(self) -> None: - hn = HumanName("Velasquez y Garcia, Dr. Juan Q.") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test84(self) -> None: - hn = HumanName("Velasquez y Garcia, Dr. Juan Q., Jr.") - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test85(self) -> None: - hn = HumanName("Velasquez y Garcia, Dr. Juan Q. III") - self.m(hn.middle, "Q.", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test86(self) -> None: - hn = HumanName("Juan Q. Xavier de la Vega") - self.m(hn.first, "Juan", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.last, "de la Vega", hn) - - def test87(self) -> None: - hn = HumanName("Juan Q. Xavier de la Vega, Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "Jr.", hn) - - def test88(self) -> None: - hn = HumanName("Juan Q. Xavier de la Vega III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "III", hn) - - def test89(self) -> None: - hn = HumanName("de la Vega, Juan Q. Xavier") - self.m(hn.first, "Juan", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.last, "de la Vega", hn) - - def test90(self) -> None: - hn = HumanName("de la Vega, Juan Q. Xavier, Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "Jr.", hn) - - def test91(self) -> None: - hn = HumanName("de la Vega, Juan Q. Xavier III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "III", hn) - - def test92(self) -> None: - hn = HumanName("Dr. Juan Q. Xavier de la Vega") - self.m(hn.first, "Juan", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.last, "de la Vega", hn) - - def test93(self) -> None: - hn = HumanName("Dr. Juan Q. Xavier de la Vega, Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "Jr.", hn) - - def test94(self) -> None: - hn = HumanName("Dr. Juan Q. Xavier de la Vega III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "III", hn) - - def test95(self) -> None: - hn = HumanName("de la Vega, Dr. Juan Q. Xavier") - self.m(hn.first, "Juan", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.last, "de la Vega", hn) - - def test96(self) -> None: - hn = HumanName("de la Vega, Dr. Juan Q. Xavier, Jr.") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "Jr.", hn) - - def test97(self) -> None: - hn = HumanName("de la Vega, Dr. Juan Q. Xavier III") - self.m(hn.first, "Juan", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.last, "de la Vega", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "III", hn) - - def test98(self) -> None: - hn = HumanName("Juan Q. Xavier Velasquez y Garcia") - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test99(self) -> None: - hn = HumanName("Juan Q. Xavier Velasquez y Garcia, Jr.") - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test100(self) -> None: - hn = HumanName("Juan Q. Xavier Velasquez y Garcia III") - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test101(self) -> None: - hn = HumanName("Velasquez y Garcia, Juan Q. Xavier") - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test102(self) -> None: - hn = HumanName("Velasquez y Garcia, Juan Q. Xavier, Jr.") - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test103(self) -> None: - hn = HumanName("Velasquez y Garcia, Juan Q. Xavier III") - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test104(self) -> None: - hn = HumanName("Dr. Juan Q. Xavier Velasquez y Garcia") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test105(self) -> None: - hn = HumanName("Dr. Juan Q. Xavier Velasquez y Garcia, Jr.") - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test106(self) -> None: - hn = HumanName("Dr. Juan Q. Xavier Velasquez y Garcia III") - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test107(self) -> None: - hn = HumanName("Velasquez y Garcia, Dr. Juan Q. Xavier") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - - def test108(self) -> None: - hn = HumanName("Velasquez y Garcia, Dr. Juan Q. Xavier, Jr.") - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "Jr.", hn) - - def test109(self) -> None: - hn = HumanName("Velasquez y Garcia, Dr. Juan Q. Xavier III") - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.first, "Juan", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.last, "Velasquez y Garcia", hn) - self.m(hn.suffix, "III", hn) - - def test110(self) -> None: - hn = HumanName("John Doe, CLU, CFP, LUTC") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "CLU, CFP, LUTC", hn) - - def test111(self) -> None: - hn = HumanName("John P. Doe, CLU, CFP, LUTC") - self.m(hn.first, "John", hn) - self.m(hn.middle, "P.", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "CLU, CFP, LUTC", hn) - - def test112(self) -> None: - hn = HumanName("Dr. John P. Doe-Ray, CLU, CFP, LUTC") - self.m(hn.first, "John", hn) - self.m(hn.middle, "P.", hn) - self.m(hn.last, "Doe-Ray", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.suffix, "CLU, CFP, LUTC", hn) - - def test113(self) -> None: - hn = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "P.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe-Ray", hn) - self.m(hn.suffix, "CLU, CFP, LUTC", hn) - - def test115(self) -> None: - hn = HumanName("Hon. Barrington P. Doe-Ray, Jr.") - self.m(hn.title, "Hon.", hn) - self.m(hn.middle, "P.", hn) - self.m(hn.first, "Barrington", hn) - self.m(hn.last, "Doe-Ray", hn) - - def test116(self) -> None: - hn = HumanName("Doe-Ray, Hon. Barrington P. Jr., CFP, LUTC") - self.m(hn.title, "Hon.", hn) - self.m(hn.middle, "P.", hn) - self.m(hn.first, "Barrington", hn) - self.m(hn.last, "Doe-Ray", hn) - self.m(hn.suffix, "Jr., CFP, LUTC", hn) - - def test117(self) -> None: - hn = HumanName("Rt. Hon. Paul E. Mary") - self.m(hn.title, "Rt. Hon.", hn) - self.m(hn.first, "Paul", hn) - self.m(hn.middle, "E.", hn) - self.m(hn.last, "Mary", hn) - - def test119(self) -> None: - hn = HumanName("Lord God Almighty") - self.m(hn.title, "Lord", hn) - self.m(hn.first, "God", hn) - self.m(hn.last, "Almighty", hn) - - -class HumanNameConjunctionTestCase(HumanNameTestBase): - # Last name with conjunction - def test_last_name_with_conjunction(self) -> None: - hn = HumanName('Jose Aznar y Lopez') - self.m(hn.first, "Jose", hn) - self.m(hn.last, "Aznar y Lopez", hn) - - def test_multiple_conjunctions(self) -> None: - hn = HumanName("part1 of The part2 of the part3 and part4") - self.m(hn.first, "part1 of The part2 of the part3 and part4", hn) - - def test_multiple_conjunctions2(self) -> None: - hn = HumanName("part1 of and The part2 of the part3 And part4") - self.m(hn.first, "part1 of and The part2 of the part3 And part4", hn) - - def test_ends_with_conjunction(self) -> None: - hn = HumanName("Jon Dough and") - self.m(hn.first, "Jon", hn) - self.m(hn.last, "Dough and", hn) - - def test_ends_with_two_conjunctions(self) -> None: - hn = HumanName("Jon Dough and of") - self.m(hn.first, "Jon", hn) - self.m(hn.last, "Dough and of", hn) - - def test_starts_with_conjunction(self) -> None: - hn = HumanName("and Jon Dough") - self.m(hn.first, "and Jon", hn) - self.m(hn.last, "Dough", hn) - - def test_starts_with_two_conjunctions(self) -> None: - hn = HumanName("the and Jon Dough") - self.m(hn.first, "the and Jon", hn) - self.m(hn.last, "Dough", hn) - - # Potential conjunction/prefix treated as initial (because uppercase) - def test_uppercase_middle_initial_conflict_with_conjunction(self) -> None: - hn = HumanName('John E Smith') - self.m(hn.first, "John", hn) - self.m(hn.middle, "E", hn) - self.m(hn.last, "Smith", hn) - - def test_lowercase_middle_initial_with_period_conflict_with_conjunction(self) -> None: - hn = HumanName('john e. smith') - self.m(hn.first, "john", hn) - self.m(hn.middle, "e.", hn) - self.m(hn.last, "smith", hn) - - # The conjunction "e" can also be an initial - def test_lowercase_first_initial_conflict_with_conjunction(self) -> None: - hn = HumanName('e j smith') - self.m(hn.first, "e", hn) - self.m(hn.middle, "j", hn) - self.m(hn.last, "smith", hn) - - def test_lowercase_middle_initial_conflict_with_conjunction(self) -> None: - hn = HumanName('John e Smith') - self.m(hn.first, "John", hn) - self.m(hn.middle, "e", hn) - self.m(hn.last, "Smith", hn) - - def test_lowercase_middle_initial_and_suffix_conflict_with_conjunction(self) -> None: - hn = HumanName('John e Smith, III') - self.m(hn.first, "John", hn) - self.m(hn.middle, "e", hn) - self.m(hn.last, "Smith", hn) - self.m(hn.suffix, "III", hn) - - def test_lowercase_middle_initial_and_nocomma_suffix_conflict_with_conjunction(self) -> None: - hn = HumanName('John e Smith III') - self.m(hn.first, "John", hn) - self.m(hn.middle, "e", hn) - self.m(hn.last, "Smith", hn) - self.m(hn.suffix, "III", hn) - - def test_lowercase_middle_initial_comma_lastname_and_suffix_conflict_with_conjunction(self) -> None: - hn = HumanName('Smith, John e, III, Jr') - self.m(hn.first, "John", hn) - self.m(hn.middle, "e", hn) - self.m(hn.last, "Smith", hn) - self.m(hn.suffix, "III, Jr", hn) - - @unittest.expectedFailure - def test_two_initials_conflict_with_conjunction(self) -> None: - # Supporting this seems to screw up titles with periods in them like M.B.A. - hn = HumanName('E.T. Smith') - self.m(hn.first, "E.", hn) - self.m(hn.middle, "T.", hn) - self.m(hn.last, "Smith", hn) - - def test_couples_names(self) -> None: - hn = HumanName('John and Jane Smith') - self.m(hn.first, "John and Jane", hn) - self.m(hn.last, "Smith", hn) - - def test_couples_names_with_conjunction_lastname(self) -> None: - hn = HumanName('John and Jane Aznar y Lopez') - self.m(hn.first, "John and Jane", hn) - self.m(hn.last, "Aznar y Lopez", hn) - - def test_couple_titles(self) -> None: - hn = HumanName('Mr. and Mrs. John and Jane Smith') - self.m(hn.title, "Mr. and Mrs.", hn) - self.m(hn.first, "John and Jane", hn) - self.m(hn.last, "Smith", hn) - - def test_title_with_three_part_name_last_initial_is_suffix_uppercase_no_period(self) -> None: - hn = HumanName("King John Alexander V") - self.m(hn.title, "King", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Alexander", hn) - self.m(hn.suffix, "V", hn) - - def test_four_name_parts_with_suffix_that_could_be_initial_lowercase_no_period(self) -> None: - hn = HumanName("larry james edward johnson v") - self.m(hn.first, "larry", hn) - self.m(hn.middle, "james edward", hn) - self.m(hn.last, "johnson", hn) - self.m(hn.suffix, "v", hn) - - def test_four_name_parts_with_suffix_that_could_be_initial_uppercase_no_period(self) -> None: - hn = HumanName("Larry James Johnson I") - self.m(hn.first, "Larry", hn) - self.m(hn.middle, "James", hn) - self.m(hn.last, "Johnson", hn) - self.m(hn.suffix, "I", hn) - - def test_roman_numeral_initials(self) -> None: - hn = HumanName("Larry V I") - self.m(hn.first, "Larry", hn) - self.m(hn.middle, "V", hn) - self.m(hn.last, "I", hn) - self.m(hn.suffix, "", hn) - - def test_roman_numeral_suffix_not_in_suffix_list(self) -> None: - # VI-X are not in the suffix word lists, so they reach the - # is_roman_numeral(nxt) branch rather than are_suffixes() - hn = HumanName("John Smith VI") - self.m(hn.first, "John", hn) - self.m(hn.last, "Smith", hn) - self.m(hn.suffix, "VI", hn) - - # tests for Rev. title (Reverend) - def test124(self) -> None: - hn = HumanName("Rev. John A. Kenneth Doe") - self.m(hn.title, "Rev.", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - - def test125(self) -> None: - hn = HumanName("Rev John A. Kenneth Doe") - self.m(hn.title, "Rev", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - - def test126(self) -> None: - hn = HumanName("Doe, Rev. John A. Jr.") - self.m(hn.title, "Rev.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - self.m(hn.suffix, "Jr.", hn) - - def test127(self) -> None: - hn = HumanName("Buca di Beppo") - self.m(hn.first, "Buca", hn) - self.m(hn.last, "di Beppo", hn) - - def test_le_as_last_name(self) -> None: - hn = HumanName("Yin Le") - self.m(hn.first, "Yin", hn) - self.m(hn.last, "Le", hn) - - def test_le_as_last_name_with_middle_initial(self) -> None: - hn = HumanName("Yin a Le") - self.m(hn.first, "Yin", hn) - self.m(hn.middle, "a", hn) - self.m(hn.last, "Le", hn) - - def test_conjunction_in_an_address_with_a_title(self) -> None: - hn = HumanName("His Excellency Lord Duncan") - self.m(hn.title, "His Excellency Lord", hn) - self.m(hn.last, "Duncan", hn) - - @unittest.expectedFailure - def test_conjunction_in_an_address_with_a_first_name_title(self) -> None: - hn = HumanName("Her Majesty Queen Elizabeth") - self.m(hn.title, "Her Majesty Queen", hn) - # if you want to be technical, Queen is in FIRST_NAME_TITLES - self.m(hn.first, "Elizabeth", hn) - - def test_name_is_conjunctions(self) -> None: - hn = HumanName("e and e") - self.m(hn.first, "e and e", hn) - - -class ConstantsCustomization(HumanNameTestBase): - - def test_add_title(self) -> None: - hn = HumanName("Te Awanui-a-Rangi Black", constants=None) - start_len = len(hn.C.titles) - self.assertTrue(start_len > 0) - hn.C.titles.add('te') - self.assertEqual(start_len + 1, len(hn.C.titles)) - hn.parse_full_name() - self.m(hn.title, "Te", hn) - self.m(hn.first, "Awanui-a-Rangi", hn) - self.m(hn.last, "Black", hn) - - def test_remove_title(self) -> None: - hn = HumanName("Hon Solo", constants=None) - start_len = len(hn.C.titles) - self.assertTrue(start_len > 0) - hn.C.titles.remove('hon') - self.assertEqual(start_len - 1, len(hn.C.titles)) - hn.parse_full_name() - self.m(hn.first, "Hon", hn) - self.m(hn.last, "Solo", hn) - - def test_add_multiple_arguments(self) -> None: - hn = HumanName("Assoc Dean of Chemistry Robert Johns", constants=None) - hn.C.titles.add('dean', 'Chemistry') - hn.parse_full_name() - self.m(hn.title, "Assoc Dean of Chemistry", hn) - self.m(hn.first, "Robert", hn) - self.m(hn.last, "Johns", hn) - - def test_instances_can_have_own_constants(self) -> None: - hn = HumanName("", None) - hn2 = HumanName("") - hn.C.titles.remove('hon') - self.assertEqual('hon' in hn.C.titles, False) - self.assertEqual(hn.has_own_config, True) - self.assertEqual('hon' in hn2.C.titles, True) - self.assertEqual(hn2.has_own_config, False) - - def test_can_change_global_constants(self) -> None: - hn = HumanName("") - hn2 = HumanName("") - hn.C.titles.remove('hon') - self.assertEqual('hon' in hn.C.titles, False) - self.assertEqual('hon' in hn2.C.titles, False) - self.assertEqual(hn.has_own_config, False) - self.assertEqual(hn2.has_own_config, False) - # clean up so we don't mess up other tests - hn.C.titles.add('hon') - - def test_remove_multiple_arguments(self) -> None: - hn = HumanName("Ms Hon Solo", constants=None) - hn.C.titles.remove('hon', 'ms') - hn.parse_full_name() - self.m(hn.first, "Ms", hn) - self.m(hn.middle, "Hon", hn) - self.m(hn.last, "Solo", hn) - - def test_chain_multiple_arguments(self) -> None: - hn = HumanName("Dean Ms Hon Solo", constants=None) - hn.C.titles.remove('hon', 'ms').add('dean') - hn.parse_full_name() - self.m(hn.title, "Dean", hn) - self.m(hn.first, "Ms", hn) - self.m(hn.middle, "Hon", hn) - self.m(hn.last, "Solo", hn) - - def test_empty_attribute_default(self) -> None: - from nameparser.config import CONSTANTS - _orig = CONSTANTS.empty_attribute_default - CONSTANTS.empty_attribute_default = None - hn = HumanName("") - self.m(hn.title, None, hn) - self.m(hn.first, None, hn) - self.m(hn.middle, None, hn) - self.m(hn.last, None, hn) - self.m(hn.suffix, None, hn) - self.m(hn.nickname, None, hn) - CONSTANTS.empty_attribute_default = _orig - - def test_empty_attribute_on_instance(self) -> None: - hn = HumanName("", None) - hn.C.empty_attribute_default = None - self.m(hn.title, None, hn) - self.m(hn.first, None, hn) - self.m(hn.middle, None, hn) - self.m(hn.last, None, hn) - self.m(hn.suffix, None, hn) - self.m(hn.nickname, None, hn) - - def test_none_empty_attribute_string_formatting(self) -> None: - hn = HumanName("", None) - hn.C.empty_attribute_default = None - self.assertEqual('', str(hn), hn) - - def test_add_constant_with_explicit_encoding(self) -> None: - c = Constants() - c.titles.add_with_encoding(b'b\351ck', encoding='latin_1') - self.assertIn('béck', c.titles) - - -class NicknameTestCase(HumanNameTestBase): - # https://code.google.com/p/python-nameparser/issues/detail?id=33 - def test_nickname_in_parenthesis(self) -> None: - hn = HumanName("Benjamin (Ben) Franklin") - self.m(hn.first, "Benjamin", hn) - self.m(hn.middle, "", hn) - self.m(hn.last, "Franklin", hn) - self.m(hn.nickname, "Ben", hn) - - def test_two_word_nickname_in_parenthesis(self) -> None: - hn = HumanName("Benjamin (Big Ben) Franklin") - self.m(hn.first, "Benjamin", hn) - self.m(hn.middle, "", hn) - self.m(hn.last, "Franklin", hn) - self.m(hn.nickname, "Big Ben", hn) - - def test_two_words_in_quotes(self) -> None: - hn = HumanName('Benjamin "Big Ben" Franklin') - self.m(hn.first, "Benjamin", hn) - self.m(hn.middle, "", hn) - self.m(hn.last, "Franklin", hn) - self.m(hn.nickname, "Big Ben", hn) - - def test_nickname_in_parenthesis_with_comma(self) -> None: - hn = HumanName("Franklin, Benjamin (Ben)") - self.m(hn.first, "Benjamin", hn) - self.m(hn.middle, "", hn) - self.m(hn.last, "Franklin", hn) - self.m(hn.nickname, "Ben", hn) - - def test_nickname_in_parenthesis_with_comma_and_suffix(self) -> None: - hn = HumanName("Franklin, Benjamin (Ben), Jr.") - self.m(hn.first, "Benjamin", hn) - self.m(hn.middle, "", hn) - self.m(hn.last, "Franklin", hn) - self.m(hn.suffix, "Jr.", hn) - self.m(hn.nickname, "Ben", hn) - - def test_nickname_in_single_quotes(self) -> None: - hn = HumanName("Benjamin 'Ben' Franklin") - self.m(hn.first, "Benjamin", hn) - self.m(hn.middle, "", hn) - self.m(hn.last, "Franklin", hn) - self.m(hn.nickname, "Ben", hn) - - def test_nickname_in_double_quotes(self) -> None: - hn = HumanName("Benjamin \"Ben\" Franklin") - self.m(hn.first, "Benjamin", hn) - self.m(hn.middle, "", hn) - self.m(hn.last, "Franklin", hn) - self.m(hn.nickname, "Ben", hn) - - def test_single_quotes_on_first_name_not_treated_as_nickname(self) -> None: - hn = HumanName("Brian Andrew O'connor") - self.m(hn.first, "Brian", hn) - self.m(hn.middle, "Andrew", hn) - self.m(hn.last, "O'connor", hn) - self.m(hn.nickname, "", hn) - - def test_single_quotes_on_both_name_not_treated_as_nickname(self) -> None: - hn = HumanName("La'tanya O'connor") - self.m(hn.first, "La'tanya", hn) - self.m(hn.middle, "", hn) - self.m(hn.last, "O'connor", hn) - self.m(hn.nickname, "", hn) - - def test_single_quotes_on_end_of_last_name_not_treated_as_nickname(self) -> None: - hn = HumanName("Mari' Aube'") - self.m(hn.first, "Mari'", hn) - self.m(hn.middle, "", hn) - self.m(hn.last, "Aube'", hn) - self.m(hn.nickname, "", hn) - - def test_okina_inside_name_not_treated_as_nickname(self) -> None: - hn = HumanName("Harrieta Keōpūolani Nāhiʻenaʻena") - self.m(hn.first, "Harrieta", hn) - self.m(hn.middle, "Keōpūolani", hn) - self.m(hn.last, "Nāhiʻenaʻena", hn) - self.m(hn.nickname, "", hn) - - def test_single_quotes_not_treated_as_nickname_Hawaiian_example(self) -> None: - hn = HumanName("Harietta Keopuolani Nahi'ena'ena") - self.m(hn.first, "Harietta", hn) - self.m(hn.middle, "Keopuolani", hn) - self.m(hn.last, "Nahi'ena'ena", hn) - self.m(hn.nickname, "", hn) - - def test_single_quotes_not_treated_as_nickname_Kenyan_example(self) -> None: - hn = HumanName("Naomi Wambui Ng'ang'a") - self.m(hn.first, "Naomi", hn) - self.m(hn.middle, "Wambui", hn) - self.m(hn.last, "Ng'ang'a", hn) - self.m(hn.nickname, "", hn) - - def test_single_quotes_not_treated_as_nickname_Samoan_example(self) -> None: - hn = HumanName("Va'apu'u Vitale") - self.m(hn.first, "Va'apu'u", hn) - self.m(hn.middle, "", hn) - self.m(hn.last, "Vitale", hn) - self.m(hn.nickname, "", hn) - - # http://code.google.com/p/python-nameparser/issues/detail?id=17 - def test_parenthesis_are_removed_from_name(self) -> None: - hn = HumanName("John Jones (Unknown)") - self.m(hn.first, "John", hn) - self.m(hn.last, "Jones", hn) - # not testing the nicknames because we don't actually care - # about Google Docs here - - def test_duplicate_parenthesis_are_removed_from_name(self) -> None: - hn = HumanName("John Jones (Google Docs), Jr. (Unknown)") - self.m(hn.first, "John", hn) - self.m(hn.last, "Jones", hn) - self.m(hn.suffix, "Jr.", hn) - - def test_nickname_and_last_name(self) -> None: - hn = HumanName('"Rick" Edmonds') - self.m(hn.first, "", hn) - self.m(hn.last, "Edmonds", hn) - self.m(hn.nickname, "Rick", hn) - - @unittest.expectedFailure - def test_nickname_and_last_name_with_title(self) -> None: - hn = HumanName('Senator "Rick" Edmonds') - self.m(hn.title, "Senator", hn) - self.m(hn.first, "", hn) - self.m(hn.last, "Edmonds", hn) - self.m(hn.nickname, "Rick", hn) - - -# class MaidenNameTestCase(HumanNameTestBase): -# -# def test_parenthesis_and_quotes_together(self): -# hn = HumanName("Jennifer 'Jen' Jones (Duff)") -# self.m(hn.first, "Jennifer", hn) -# self.m(hn.last, "Jones", hn) -# self.m(hn.nickname, "Jen", hn) -# self.m(hn.maiden, "Duff", hn) -# -# def test_maiden_name_with_nee(self): -# # https://en.wiktionary.org/wiki/née -# hn = HumanName("Mary Toogood nee Johnson") -# self.m(hn.first, "Mary", hn) -# self.m(hn.last, "Toogood", hn) -# self.m(hn.maiden, "Johnson", hn) -# -# def test_maiden_name_with_accented_nee(self): -# # https://en.wiktionary.org/wiki/née -# hn = HumanName("Mary Toogood née Johnson") -# self.m(hn.first, "Mary", hn) -# self.m(hn.last, "Toogood", hn) -# self.m(hn.maiden, "Johnson", hn) -# -# def test_maiden_name_with_nee_and_comma(self): -# # https://en.wiktionary.org/wiki/née -# hn = HumanName("Mary Toogood, née Johnson") -# self.m(hn.first, "Mary", hn) -# self.m(hn.last, "Toogood", hn) -# self.m(hn.maiden, "Johnson", hn) -# -# def test_maiden_name_with_nee_with_parenthesis(self): -# hn = HumanName("Mary Toogood (nee Johnson)") -# self.m(hn.first, "Mary", hn) -# self.m(hn.last, "Toogood", hn) -# self.m(hn.maiden, "Johnson", hn) -# -# def test_maiden_name_with_parenthesis(self): -# hn = HumanName("Mary Toogood (Johnson)") -# self.m(hn.first, "Mary", hn) -# self.m(hn.last, "Toogood", hn) -# self.m(hn.maiden, "Johnson", hn) -# - -class PrefixesTestCase(HumanNameTestBase): - - def test_prefix(self) -> None: - hn = HumanName("Juan del Sur") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "del Sur", hn) - - def test_prefix_with_period(self) -> None: - hn = HumanName("Jill St. John") - self.m(hn.first, "Jill", hn) - self.m(hn.last, "St. John", hn) - - def test_prefix_before_two_part_last_name(self) -> None: - hn = HumanName("pennie von bergen wessels") - self.m(hn.first, "pennie", hn) - self.m(hn.last, "von bergen wessels", hn) - - def test_prefix_is_first_name(self) -> None: - hn = HumanName("Van Johnson") - self.m(hn.first, "Van", hn) - self.m(hn.last, "Johnson", hn) - - def test_prefix_is_first_name_with_middle_name(self) -> None: - hn = HumanName("Van Jeremy Johnson") - self.m(hn.first, "Van", hn) - self.m(hn.middle, "Jeremy", hn) - self.m(hn.last, "Johnson", hn) - - def test_prefix_before_two_part_last_name_with_suffix(self) -> None: - hn = HumanName("pennie von bergen wessels III") - self.m(hn.first, "pennie", hn) - self.m(hn.last, "von bergen wessels", hn) - self.m(hn.suffix, "III", hn) - - def test_prefix_before_two_part_last_name_with_acronym_suffix(self) -> None: - hn = HumanName("pennie von bergen wessels M.D.") - self.m(hn.first, "pennie", hn) - self.m(hn.last, "von bergen wessels", hn) - self.m(hn.suffix, "M.D.", hn) - - def test_two_part_last_name_with_suffix_comma(self) -> None: - hn = HumanName("pennie von bergen wessels, III") - self.m(hn.first, "pennie", hn) - self.m(hn.last, "von bergen wessels", hn) - self.m(hn.suffix, "III", hn) - - def test_two_part_last_name_with_suffix(self) -> None: - hn = HumanName("von bergen wessels, pennie III") - self.m(hn.first, "pennie", hn) - self.m(hn.last, "von bergen wessels", hn) - self.m(hn.suffix, "III", hn) - - def test_last_name_two_part_last_name_with_two_suffixes(self) -> None: - hn = HumanName("von bergen wessels MD, pennie III") - self.m(hn.first, "pennie", hn) - self.m(hn.last, "von bergen wessels", hn) - self.m(hn.suffix, "MD, III", hn) - - def test_comma_two_part_last_name_with_acronym_suffix(self) -> None: - hn = HumanName("von bergen wessels, pennie MD") - self.m(hn.first, "pennie", hn) - self.m(hn.last, "von bergen wessels", hn) - self.m(hn.suffix, "MD", hn) - - def test_comma_two_part_last_name_with_suffix_in_first_part(self) -> None: - # I'm kinda surprised this works, not really sure if this is a - # realistic place for a suffix to be. - hn = HumanName("von bergen wessels MD, pennie") - self.m(hn.first, "pennie", hn) - self.m(hn.last, "von bergen wessels", hn) - self.m(hn.suffix, "MD", hn) - - def test_title_two_part_last_name_with_suffix_in_first_part(self) -> None: - hn = HumanName("pennie von bergen wessels MD, III") - self.m(hn.first, "pennie", hn) - self.m(hn.last, "von bergen wessels", hn) - self.m(hn.suffix, "MD, III", hn) - - def test_portuguese_dos(self) -> None: - hn = HumanName("Rafael Sousa dos Anjos") - self.m(hn.first, "Rafael", hn) - self.m(hn.middle, "Sousa", hn) - self.m(hn.last, "dos Anjos", hn) - - def test_portuguese_prefixes(self) -> None: - hn = HumanName("Joao da Silva do Amaral de Souza") - self.m(hn.first, "Joao", hn) - self.m(hn.middle, "da Silva do Amaral", hn) - self.m(hn.last, "de Souza", hn) - - def test_three_conjunctions(self) -> None: - hn = HumanName("Dr. Juan Q. Xavier de la dos Vega III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la dos Vega", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "III", hn) - - def test_lastname_three_conjunctions(self) -> None: - hn = HumanName("de la dos Vega, Dr. Juan Q. Xavier III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la dos Vega", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "III", hn) - - def test_comma_three_conjunctions(self) -> None: - hn = HumanName("Dr. Juan Q. Xavier de la dos Vega, III") - self.m(hn.first, "Juan", hn) - self.m(hn.last, "de la dos Vega", hn) - self.m(hn.title, "Dr.", hn) - self.m(hn.middle, "Q. Xavier", hn) - self.m(hn.suffix, "III", hn) - - -class SuffixesTestCase(HumanNameTestBase): - - def test_suffix(self) -> None: - hn = HumanName("Joe Franklin Jr") - self.m(hn.first, "Joe", hn) - self.m(hn.last, "Franklin", hn) - self.m(hn.suffix, "Jr", hn) - - def test_suffix_with_periods(self) -> None: - hn = HumanName("Joe Dentist D.D.S.") - self.m(hn.first, "Joe", hn) - self.m(hn.last, "Dentist", hn) - self.m(hn.suffix, "D.D.S.", hn) - - def test_two_suffixes(self) -> None: - hn = HumanName("Kenneth Clarke QC MP") - self.m(hn.first, "Kenneth", hn) - self.m(hn.last, "Clarke", hn) - # NOTE: this adds a comma when the original format did not have one. - # not ideal but at least its in the right bucket - self.m(hn.suffix, "QC, MP", hn) - - def test_two_suffixes_lastname_comma_format(self) -> None: - hn = HumanName("Washington Jr. MD, Franklin") - self.m(hn.first, "Franklin", hn) - self.m(hn.last, "Washington", hn) - # NOTE: this adds a comma when the original format did not have one. - self.m(hn.suffix, "Jr., MD", hn) - - def test_two_suffixes_suffix_comma_format(self) -> None: - hn = HumanName("Franklin Washington, Jr. MD") - self.m(hn.first, "Franklin", hn) - self.m(hn.last, "Washington", hn) - self.m(hn.suffix, "Jr. MD", hn) - - def test_suffix_containing_periods(self) -> None: - hn = HumanName("Kenneth Clarke Q.C.") - self.m(hn.first, "Kenneth", hn) - self.m(hn.last, "Clarke", hn) - self.m(hn.suffix, "Q.C.", hn) - - def test_suffix_containing_periods_lastname_comma_format(self) -> None: - hn = HumanName("Clarke, Kenneth, Q.C. M.P.") - self.m(hn.first, "Kenneth", hn) - self.m(hn.last, "Clarke", hn) - self.m(hn.suffix, "Q.C. M.P.", hn) - - def test_suffix_containing_periods_suffix_comma_format(self) -> None: - hn = HumanName("Kenneth Clarke Q.C., M.P.") - self.m(hn.first, "Kenneth", hn) - self.m(hn.last, "Clarke", hn) - self.m(hn.suffix, "Q.C., M.P.", hn) - - def test_suffix_with_single_comma_format(self) -> None: - hn = HumanName("John Doe jr., MD") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "jr., MD", hn) - - def test_suffix_with_double_comma_format(self) -> None: - hn = HumanName("Doe, John jr., MD") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "jr., MD", hn) - - def test_phd_with_erroneous_space(self) -> None: - hn = HumanName("John Smith, Ph. D.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Smith", hn) - self.m(hn.suffix, "Ph. D.", hn) - - def test_phd_extracted_without_comma(self) -> None: - hn = HumanName("John Smith Ph. D.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Smith", hn) - self.m(hn.suffix, "Ph. D.", hn) - - def test_phd_conflict(self) -> None: - hn = HumanName("Adolph D") - self.m(hn.first, "Adolph", hn) - self.m(hn.last, "D", hn) - - # http://en.wikipedia.org/wiki/Ma_(surname) - - def test_potential_suffix_that_is_also_last_name(self) -> None: - hn = HumanName("Jack Ma") - self.m(hn.first, "Jack", hn) - self.m(hn.last, "Ma", hn) - - def test_potential_suffix_that_is_also_last_name_comma(self) -> None: - hn = HumanName("Ma, Jack") - self.m(hn.first, "Jack", hn) - self.m(hn.last, "Ma", hn) - - def test_potential_suffix_that_is_also_last_name_with_suffix(self) -> None: - hn = HumanName("Jack Ma Jr") - self.m(hn.first, "Jack", hn) - self.m(hn.last, "Ma", hn) - self.m(hn.suffix, "Jr", hn) - - def test_potential_suffix_that_is_also_last_name_with_suffix_comma(self) -> None: - hn = HumanName("Ma III, Jack Jr") - self.m(hn.first, "Jack", hn) - self.m(hn.last, "Ma", hn) - self.m(hn.suffix, "III, Jr", hn) - - # https://github.com/derek73/python-nameparser/issues/27 - @unittest.expectedFailure - def test_king(self) -> None: - hn = HumanName("Dr King Jr") - self.m(hn.title, "Dr", hn) - self.m(hn.last, "King", hn) - self.m(hn.suffix, "Jr", hn) - - def test_multiple_letter_suffix_with_periods(self) -> None: - hn = HumanName("John Doe Msc.Ed.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "Msc.Ed.", hn) - - def test_suffix_with_periods_with_comma(self) -> None: - hn = HumanName("John Doe, Msc.Ed.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "Msc.Ed.", hn) - - def test_suffix_with_periods_with_lastname_comma(self) -> None: - hn = HumanName("Doe, John Msc.Ed.") - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.suffix, "Msc.Ed.", hn) - - -class TitleTestCase(HumanNameTestBase): - - def test_last_name_is_also_title(self) -> None: - hn = HumanName("Amy E Maid") - self.m(hn.first, "Amy", hn) - self.m(hn.middle, "E", hn) - self.m(hn.last, "Maid", hn) - - def test_last_name_is_also_title_no_comma(self) -> None: - hn = HumanName("Dr. Martin Luther King Jr.") - self.m(hn.title, "Dr.", hn) - self.m(hn.first, "Martin", hn) - self.m(hn.middle, "Luther", hn) - self.m(hn.last, "King", hn) - self.m(hn.suffix, "Jr.", hn) - - def test_last_name_is_also_title_with_comma(self) -> None: - hn = HumanName("Dr Martin Luther King, Jr.") - self.m(hn.title, "Dr", hn) - self.m(hn.first, "Martin", hn) - self.m(hn.middle, "Luther", hn) - self.m(hn.last, "King", hn) - self.m(hn.suffix, "Jr.", hn) - - def test_last_name_is_also_title3(self) -> None: - hn = HumanName("John King") - self.m(hn.first, "John", hn) - self.m(hn.last, "King", hn) - - def test_title_with_conjunction(self) -> None: - hn = HumanName("Secretary of State Hillary Clinton") - self.m(hn.title, "Secretary of State", hn) - self.m(hn.first, "Hillary", hn) - self.m(hn.last, "Clinton", hn) - - def test_compound_title_with_conjunction(self) -> None: - hn = HumanName("Cardinal Secretary of State Hillary Clinton") - self.m(hn.title, "Cardinal Secretary of State", hn) - self.m(hn.first, "Hillary", hn) - self.m(hn.last, "Clinton", hn) - - def test_title_is_title(self) -> None: - hn = HumanName("Coach") - self.m(hn.title, "Coach", hn) - - # TODO: fix handling of U.S. - @unittest.expectedFailure - def test_chained_title_first_name_title_is_initials(self) -> None: - hn = HumanName("U.S. District Judge Marc Thomas Treadwell") - self.m(hn.title, "U.S. District Judge", hn) - self.m(hn.first, "Marc", hn) - self.m(hn.middle, "Thomas", hn) - self.m(hn.last, "Treadwell", hn) - - def test_conflict_with_chained_title_first_name_initial(self) -> None: - hn = HumanName("U. S. Grant") - self.m(hn.first, "U.", hn) - self.m(hn.middle, "S.", hn) - self.m(hn.last, "Grant", hn) - - def test_chained_title_first_name_initial_with_no_period(self) -> None: - hn = HumanName("US Magistrate Judge T Michael Putnam") - self.m(hn.title, "US Magistrate Judge", hn) - self.m(hn.first, "T", hn) - self.m(hn.middle, "Michael", hn) - self.m(hn.last, "Putnam", hn) - - def test_chained_hyphenated_title(self) -> None: - hn = HumanName("US Magistrate-Judge Elizabeth E Campbell") - self.m(hn.title, "US Magistrate-Judge", hn) - self.m(hn.first, "Elizabeth", hn) - self.m(hn.middle, "E", hn) - self.m(hn.last, "Campbell", hn) - - def test_chained_hyphenated_title_with_comma_suffix(self) -> None: - hn = HumanName("Mag-Judge Harwell G Davis, III") - self.m(hn.title, "Mag-Judge", hn) - self.m(hn.first, "Harwell", hn) - self.m(hn.middle, "G", hn) - self.m(hn.last, "Davis", hn) - self.m(hn.suffix, "III", hn) - - @unittest.expectedFailure - def test_title_multiple_titles_with_apostrophe_s(self) -> None: - hn = HumanName("The Right Hon. the President of the Queen's Bench Division") - self.m(hn.title, "The Right Hon. the President of the Queen's Bench Division", hn) - - def test_title_starts_with_conjunction(self) -> None: - hn = HumanName("The Rt Hon John Jones") - self.m(hn.title, "The Rt Hon", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Jones", hn) - - def test_conjunction_before_title(self) -> None: - hn = HumanName('The Lord of the Universe') - self.m(hn.title, "The Lord of the Universe", hn) - - def test_double_conjunction_on_title(self) -> None: - hn = HumanName('Lord of the Universe') - self.m(hn.title, "Lord of the Universe", hn) - - def test_triple_conjunction_on_title(self) -> None: - hn = HumanName('Lord and of the Universe') - self.m(hn.title, "Lord and of the Universe", hn) - - def test_multiple_conjunctions_on_multiple_titles(self) -> None: - hn = HumanName('Lord of the Universe and Associate Supreme Queen of the World Lisa Simpson') - self.m(hn.title, "Lord of the Universe and Associate Supreme Queen of the World", hn) - self.m(hn.first, "Lisa", hn) - self.m(hn.last, "Simpson", hn) - - def test_title_with_last_initial_is_suffix(self) -> None: - hn = HumanName("King John V.") - self.m(hn.title, "King", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "V.", hn) - - def test_initials_also_suffix(self) -> None: - hn = HumanName("Smith, J.R.") - self.m(hn.first, "J.R.", hn) - # self.m(hn.middle, "R.", hn) - self.m(hn.last, "Smith", hn) - - def test_two_title_parts_separated_by_periods(self) -> None: - hn = HumanName("Lt.Gen. John A. Kenneth Doe IV") - self.m(hn.title, "Lt.Gen.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.suffix, "IV", hn) - - def test_two_part_title(self) -> None: - hn = HumanName("Lt. Gen. John A. Kenneth Doe IV") - self.m(hn.title, "Lt. Gen.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.suffix, "IV", hn) - - def test_two_part_title_with_lastname_comma(self) -> None: - hn = HumanName("Doe, Lt. Gen. John A. Kenneth IV") - self.m(hn.title, "Lt. Gen.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.suffix, "IV", hn) - - def test_two_part_title_with_suffix_comma(self) -> None: - hn = HumanName("Lt. Gen. John A. Kenneth Doe, Jr.") - self.m(hn.title, "Lt. Gen.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A. Kenneth", hn) - self.m(hn.suffix, "Jr.", hn) - - def test_possible_conflict_with_middle_initial_that_could_be_suffix(self) -> None: - hn = HumanName("Doe, Rev. John V, Jr.") - self.m(hn.title, "Rev.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "V", hn) - self.m(hn.suffix, "Jr.", hn) - - def test_possible_conflict_with_suffix_that_could_be_initial(self) -> None: - hn = HumanName("Doe, Rev. John A., V, Jr.") - self.m(hn.title, "Rev.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - self.m(hn.middle, "A.", hn) - self.m(hn.suffix, "V, Jr.", hn) - - # 'ben' is removed from PREFIXES in v0.2.5 - # this test could re-enable this test if we decide to support 'ben' as a prefix - @unittest.expectedFailure - def test_ben_as_conjunction(self) -> None: - hn = HumanName("Ahmad ben Husain") - self.m(hn.first, "Ahmad", hn) - self.m(hn.last, "ben Husain", hn) - - def test_ben_as_first_name(self) -> None: - hn = HumanName("Ben Johnson") - self.m(hn.first, "Ben", hn) - self.m(hn.last, "Johnson", hn) - - def test_ben_as_first_name_with_middle_name(self) -> None: - hn = HumanName("Ben Alex Johnson") - self.m(hn.first, "Ben", hn) - self.m(hn.middle, "Alex", hn) - self.m(hn.last, "Johnson", hn) - - def test_ben_as_middle_name(self) -> None: - hn = HumanName("Alex Ben Johnson") - self.m(hn.first, "Alex", hn) - self.m(hn.middle, "Ben", hn) - self.m(hn.last, "Johnson", hn) - - # http://code.google.com/p/python-nameparser/issues/detail?id=13 - def test_last_name_also_prefix(self) -> None: - hn = HumanName("Jane Doctor") - self.m(hn.first, "Jane", hn) - self.m(hn.last, "Doctor", hn) - - def test_title_with_periods(self) -> None: - hn = HumanName("Lt.Gov. John Doe") - self.m(hn.title, "Lt.Gov.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - - def test_title_with_periods_lastname_comma(self) -> None: - hn = HumanName("Doe, Lt.Gov. John") - self.m(hn.title, "Lt.Gov.", hn) - self.m(hn.first, "John", hn) - self.m(hn.last, "Doe", hn) - - def test_mac_with_spaces(self) -> None: - hn = HumanName("Jane Mac Beth") - self.m(hn.first, "Jane", hn) - self.m(hn.last, "Mac Beth", hn) - - def test_mac_as_first_name(self) -> None: - hn = HumanName("Mac Miller") - self.m(hn.first, "Mac", hn) - self.m(hn.last, "Miller", hn) - - def test_multiple_prefixes(self) -> None: - hn = HumanName("Mike van der Velt") - self.m(hn.first, "Mike", hn) - self.m(hn.last, "van der Velt", hn) - - def test_2_same_prefixes_in_the_name(self) -> None: - hh = HumanName("Vincent van Gogh van Beethoven") - self.m(hh.first, "Vincent", hh) - self.m(hh.middle, "van Gogh", hh) - self.m(hh.last, "van Beethoven", hh) - -class HumanNameCapitalizationTestCase(HumanNameTestBase): - def test_capitalization_exception_for_III(self) -> None: - hn = HumanName('juan q. xavier velasquez y garcia iii') - hn.capitalize() - self.m(str(hn), 'Juan Q. Xavier Velasquez y Garcia III', hn) - - # FIXME: this test does not pass due to a known issue - # http://code.google.com/p/python-nameparser/issues/detail?id=22 - @unittest.expectedFailure - def test_capitalization_exception_for_already_capitalized_III_KNOWN_FAILURE(self) -> None: - hn = HumanName('juan garcia III') - hn.capitalize() - self.m(str(hn), 'Juan Garcia III', hn) - - def test_capitalize_title(self) -> None: - hn = HumanName('lt. gen. john a. kenneth doe iv') - hn.capitalize() - self.m(str(hn), 'Lt. Gen. John A. Kenneth Doe IV', hn) - - def test_capitalize_title_to_lower(self) -> None: - hn = HumanName('LT. GEN. JOHN A. KENNETH DOE IV') - hn.capitalize() - self.m(str(hn), 'Lt. Gen. John A. Kenneth Doe IV', hn) - - # Capitalization with M(a)c and hyphenated names - def test_capitalization_with_Mac_as_hyphenated_names(self) -> None: - hn = HumanName('donovan mcnabb-smith') - hn.capitalize() - self.m(str(hn), 'Donovan McNabb-Smith', hn) - - def test_capitization_middle_initial_is_also_a_conjunction(self) -> None: - hn = HumanName('scott e. werner') - hn.capitalize() - self.m(str(hn), 'Scott E. Werner', hn) - - # Leaving already-capitalized names alone - def test_no_change_to_mixed_chase(self) -> None: - hn = HumanName('Shirley Maclaine') - hn.capitalize() - self.m(str(hn), 'Shirley Maclaine', hn) - - def test_force_capitalization(self) -> None: - hn = HumanName('Shirley Maclaine') - hn.capitalize(force=True) - self.m(str(hn), 'Shirley MacLaine', hn) - - def test_capitalize_diacritics(self) -> None: - hn = HumanName('matthëus schmidt') - hn.capitalize() - self.m(str(hn), 'Matthëus Schmidt', hn) - - # http://code.google.com/p/python-nameparser/issues/detail?id=15 - def test_downcasing_mac(self) -> None: - hn = HumanName('RONALD MACDONALD') - hn.capitalize() - self.m(str(hn), 'Ronald MacDonald', hn) - - # http://code.google.com/p/python-nameparser/issues/detail?id=23 - def test_downcasing_mc(self) -> None: - hn = HumanName('RONALD MCDONALD') - hn.capitalize() - self.m(str(hn), 'Ronald McDonald', hn) - - def test_short_names_with_mac(self) -> None: - hn = HumanName('mack johnson') - hn.capitalize() - self.m(str(hn), 'Mack Johnson', hn) - - def test_portuguese_prefixes(self) -> None: - hn = HumanName("joao da silva do amaral de souza") - hn.capitalize() - self.m(str(hn), 'Joao da Silva do Amaral de Souza', hn) - - def test_capitalize_prefix_clash_on_first_name(self) -> None: - hn = HumanName("van nguyen") - hn.capitalize() - self.m(str(hn), 'Van Nguyen', hn) - - -class HumanNameOutputFormatTests(HumanNameTestBase): - - def test_formatting_init_argument(self) -> None: - hn = HumanName("Rev John A. Kenneth Doe III (Kenny)", - string_format="TEST1") - self.assertEqual(str(hn), "TEST1") - - def test_formatting_constants_attribute(self) -> None: - from nameparser.config import CONSTANTS - _orig = CONSTANTS.string_format - CONSTANTS.string_format = "TEST2" - hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") - self.assertEqual(str(hn), "TEST2") - CONSTANTS.string_format = _orig - - def test_capitalize_name_constants_attribute(self) -> None: - from nameparser.config import CONSTANTS - CONSTANTS.capitalize_name = True - hn = HumanName("bob v. de la macdole-eisenhower phd") - self.assertEqual(str(hn), "Bob V. de la MacDole-Eisenhower Ph.D.") - CONSTANTS.capitalize_name = False - - def test_force_mixed_case_capitalization_constants_attribute(self) -> None: - from nameparser.config import CONSTANTS - CONSTANTS.force_mixed_case_capitalization = True - hn = HumanName('Shirley Maclaine') - hn.capitalize() - self.assertEqual(str(hn), "Shirley MacLaine") - CONSTANTS.force_mixed_case_capitalization = False - - def test_capitalize_name_and_force_mixed_case_capitalization_constants_attributes(self) -> None: - from nameparser.config import CONSTANTS - CONSTANTS.capitalize_name = True - CONSTANTS.force_mixed_case_capitalization = True - hn = HumanName('Shirley Maclaine') - self.assertEqual(str(hn), "Shirley MacLaine") - - def test_quote_nickname_formating(self) -> None: - hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") - hn.string_format = "{title} {first} {middle} {last} {suffix} '{nickname}'" - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III 'Kenny'") - hn.string_format = "{last}, {title} {first} {middle}, {suffix} '{nickname}'" - self.assertEqual(str(hn), "Doe, Rev John A. Kenneth, III 'Kenny'") - - def test_formating_removing_keys_from_format_string(self) -> None: - hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") - hn.string_format = "{title} {first} {middle} {last} {suffix} '{nickname}'" - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III 'Kenny'") - hn.string_format = "{last}, {title} {first} {middle}, {suffix}" - self.assertEqual(str(hn), "Doe, Rev John A. Kenneth, III") - hn.string_format = "{last}, {title} {first} {middle}" - self.assertEqual(str(hn), "Doe, Rev John A. Kenneth") - hn.string_format = "{last}, {first} {middle}" - self.assertEqual(str(hn), "Doe, John A. Kenneth") - hn.string_format = "{last}, {first}" - self.assertEqual(str(hn), "Doe, John") - hn.string_format = "{first} {last}" - self.assertEqual(str(hn), "John Doe") - - def test_formating_removing_pieces_from_name_buckets(self) -> None: - hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") - hn.string_format = "{title} {first} {middle} {last} {suffix} '{nickname}'" - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III 'Kenny'") - hn.string_format = "{title} {first} {middle} {last} {suffix}" - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III") - hn.middle = '' - self.assertEqual(str(hn), "Rev John Doe III") - hn.suffix = '' - self.assertEqual(str(hn), "Rev John Doe") - hn.title = '' - self.assertEqual(str(hn), "John Doe") - - def test_formating_of_nicknames_with_parenthesis(self) -> None: - hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") - hn.string_format = "{title} {first} {middle} {last} {suffix} ({nickname})" - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III (Kenny)") - hn.nickname = '' - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III") - - def test_formating_of_nicknames_with_single_quotes(self) -> None: - hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") - hn.string_format = "{title} {first} {middle} {last} {suffix} '{nickname}'" - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III 'Kenny'") - hn.nickname = '' - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III") - - def test_formating_of_nicknames_with_double_quotes(self) -> None: - hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") - hn.string_format = "{title} {first} {middle} {last} {suffix} \"{nickname}\"" - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III \"Kenny\"") - hn.nickname = '' - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III") - - def test_formating_of_nicknames_in_middle(self) -> None: - hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") - hn.string_format = "{title} {first} ({nickname}) {middle} {last} {suffix}" - self.assertEqual(str(hn), "Rev John (Kenny) A. Kenneth Doe III") - hn.nickname = '' - self.assertEqual(str(hn), "Rev John A. Kenneth Doe III") - - def test_remove_emojis(self) -> None: - hn = HumanName("Sam Smith 😊") - self.m(hn.first, "Sam", hn) - self.m(hn.last, "Smith", hn) - self.assertEqual(str(hn), "Sam Smith") - - def test_keep_non_emojis(self) -> None: - hn = HumanName("∫≜⩕ Smith 😊") - self.m(hn.first, "∫≜⩕", hn) - self.m(hn.last, "Smith", hn) - self.assertEqual(str(hn), "∫≜⩕ Smith") - - def test_keep_emojis(self) -> None: - from nameparser.config import Constants - constants = Constants() - constants.regexes.emoji = False - hn = HumanName("∫≜⩕ Smith😊", constants) - self.m(hn.first, "∫≜⩕", hn) - self.m(hn.last, "Smith😊", hn) - self.assertEqual(str(hn), "∫≜⩕ Smith😊") - # test cleanup - - -class InitialsTestCase(HumanNameTestBase): - def test_initials(self) -> None: - hn = HumanName("Andrew Boris Petersen") - self.m(hn.initials(), "A. B. P.", hn) - - def test_initials_simple_name(self) -> None: - hn = HumanName("John Doe") - self.m(hn.initials(), "J. D.", hn) - hn = HumanName("John Doe", initials_format="{first} {last}") - self.m(hn.initials(), "J. D.", hn) - hn = HumanName("John Doe", initials_format="{last}") - self.m(hn.initials(), "D.", hn) - hn = HumanName("John Doe", initials_format="{first}") - self.m(hn.initials(), "J.", hn) - hn = HumanName("John Doe", initials_format="{middle}") - self.m(hn.initials(), "", hn) - - def test_initials_complex_name(self) -> None: - hn = HumanName("Doe, John A. Kenneth, Jr.") - self.m(hn.initials(), "J. A. K. D.", hn) - - def test_initials_format(self) -> None: - hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{first} {middle}") - self.m(hn.initials(), "J. A. K.", hn) - hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{first} {last}") - self.m(hn.initials(), "J. D.", hn) - hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{middle} {last}") - self.m(hn.initials(), "A. K. D.", hn) - hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{first}, {last}") - self.m(hn.initials(), "J., D.", hn) - - def test_initials_format_constants(self) -> None: - from nameparser.config import CONSTANTS - _orig = CONSTANTS.initials_format - CONSTANTS.initials_format = "{first} {last}" - hn = HumanName("Doe, John A. Kenneth, Jr.") - self.m(hn.initials(), "J. D.", hn) - CONSTANTS.initials_format = "{first} {last}" - hn = HumanName("Doe, John A. Kenneth, Jr.") - self.m(hn.initials(), "J. D.", hn) - CONSTANTS.initials_format = _orig - - def test_initials_delimiter(self) -> None: - hn = HumanName("Doe, John A. Kenneth, Jr.", initials_delimiter=";") - self.m(hn.initials(), "J; A; K; D;", hn) - - def test_initials_delimiter_constants(self) -> None: - from nameparser.config import CONSTANTS - _orig = CONSTANTS.initials_delimiter - CONSTANTS.initials_delimiter = ";" - hn = HumanName("Doe, John A. Kenneth, Jr.") - self.m(hn.initials(), "J; A; K; D;", hn) - CONSTANTS.initials_delimiter = _orig - - def test_initials_list(self) -> None: - hn = HumanName("Andrew Boris Petersen") - self.m(hn.initials_list(), ["A", "B", "P"], hn) - - def test_initials_list_complex_name(self) -> None: - hn = HumanName("Doe, John A. Kenneth, Jr.") - self.m(hn.initials_list(), ["J", "A", "K", "D"], hn) - - def test_initials_with_prefix_firstname(self) -> None: - hn = HumanName("Van Jeremy Johnson") - self.m(hn.initials_list(), ["V", "J", "J"], hn) - - def test_initials_with_prefix(self) -> None: - hn = HumanName("Alex van Johnson") - self.m(hn.initials_list(), ["A", "J"], hn) - - def test_constructor_first(self) -> None: - hn = HumanName(first="TheName") - self.assertFalse(hn.unparsable) - self.m(hn.first, "TheName", hn) - - def test_constructor_middle(self) -> None: - hn = HumanName(middle="TheName") - self.assertFalse(hn.unparsable) - self.m(hn.middle, "TheName", hn) - - def test_constructor_last(self) -> None: - hn = HumanName(last="TheName") - self.assertFalse(hn.unparsable) - self.m(hn.last, "TheName", hn) - - def test_constructor_title(self) -> None: - hn = HumanName(title="TheName") - self.assertFalse(hn.unparsable) - self.m(hn.title, "TheName", hn) - - def test_constructor_suffix(self) -> None: - hn = HumanName(suffix="TheName") - self.assertFalse(hn.unparsable) - self.m(hn.suffix, "TheName", hn) - - def test_constructor_nickname(self) -> None: - hn = HumanName(nickname="TheName") - self.assertFalse(hn.unparsable) - self.m(hn.nickname, "TheName", hn) - - def test_constructor_multiple(self) -> None: - hn = HumanName(first="TheName", last="lastname", title="mytitle", full_name="donotparse") - self.assertFalse(hn.unparsable) - self.m(hn.first, "TheName", hn) - self.m(hn.last, "lastname", hn) - self.m(hn.title, "mytitle", hn) - - -TEST_NAMES = ( - "John Doe", - "John Doe, Jr.", - "John Doe III", - "Doe, John", - "Doe, John, Jr.", - "Doe, John III", - "John A. Doe", - "John A. Doe, Jr.", - "John A. Doe III", - "Doe, John A.", - "Doe, John A., Jr.", - "Doe, John A. III", - "John A. Kenneth Doe", - "John A. Kenneth Doe, Jr.", - "John A. Kenneth Doe III", - "Doe, John A. Kenneth", - "Doe, John A. Kenneth, Jr.", - "Doe, John A. Kenneth III", - "Dr. John Doe", - "Dr. John Doe, Jr.", - "Dr. John Doe III", - "Doe, Dr. John", - "Doe, Dr. John, Jr.", - "Doe, Dr. John III", - "Dr. John A. Doe", - "Dr. John A. Doe, Jr.", - "Dr. John A. Doe III", - "Doe, Dr. John A.", - "Doe, Dr. John A. Jr.", - "Doe, Dr. John A. III", - "Dr. John A. Kenneth Doe", - "Dr. John A. Kenneth Doe, Jr.", - "Dr. John A. Kenneth Doe III", - "Doe, Dr. John A. Kenneth", - "Doe, Dr. John A. Kenneth Jr.", - "Doe, Dr. John A. Kenneth III", - "Juan de la Vega", - "Juan de la Vega, Jr.", - "Juan de la Vega III", - "de la Vega, Juan", - "de la Vega, Juan, Jr.", - "de la Vega, Juan III", - "Juan Velasquez y Garcia", - "Juan Velasquez y Garcia, Jr.", - "Juan Velasquez y Garcia III", - "Velasquez y Garcia, Juan", - "Velasquez y Garcia, Juan, Jr.", - "Velasquez y Garcia, Juan III", - "Dr. Juan de la Vega", - "Dr. Juan de la Vega, Jr.", - "Dr. Juan de la Vega III", - "de la Vega, Dr. Juan", - "de la Vega, Dr. Juan, Jr.", - "de la Vega, Dr. Juan III", - "Dr. Juan Velasquez y Garcia", - "Dr. Juan Velasquez y Garcia, Jr.", - "Dr. Juan Velasquez y Garcia III", - "Velasquez y Garcia, Dr. Juan", - "Velasquez y Garcia, Dr. Juan, Jr.", - "Velasquez y Garcia, Dr. Juan III", - "Juan Q. de la Vega", - "Juan Q. de la Vega, Jr.", - "Juan Q. de la Vega III", - "de la Vega, Juan Q.", - "de la Vega, Juan Q., Jr.", - "de la Vega, Juan Q. III", - "Juan Q. Velasquez y Garcia", - "Juan Q. Velasquez y Garcia, Jr.", - "Juan Q. Velasquez y Garcia III", - "Velasquez y Garcia, Juan Q.", - "Velasquez y Garcia, Juan Q., Jr.", - "Velasquez y Garcia, Juan Q. III", - "Dr. Juan Q. de la Vega", - "Dr. Juan Q. de la Vega, Jr.", - "Dr. Juan Q. de la Vega III", - "de la Vega, Dr. Juan Q.", - "de la Vega, Dr. Juan Q., Jr.", - "de la Vega, Dr. Juan Q. III", - "Dr. Juan Q. Velasquez y Garcia", - "Dr. Juan Q. Velasquez y Garcia, Jr.", - "Dr. Juan Q. Velasquez y Garcia III", - "Velasquez y Garcia, Dr. Juan Q.", - "Velasquez y Garcia, Dr. Juan Q., Jr.", - "Velasquez y Garcia, Dr. Juan Q. III", - "Juan Q. Xavier de la Vega", - "Juan Q. Xavier de la Vega, Jr.", - "Juan Q. Xavier de la Vega III", - "de la Vega, Juan Q. Xavier", - "de la Vega, Juan Q. Xavier, Jr.", - "de la Vega, Juan Q. Xavier III", - "Juan Q. Xavier Velasquez y Garcia", - "Juan Q. Xavier Velasquez y Garcia, Jr.", - "Juan Q. Xavier Velasquez y Garcia III", - "Velasquez y Garcia, Juan Q. Xavier", - "Velasquez y Garcia, Juan Q. Xavier, Jr.", - "Velasquez y Garcia, Juan Q. Xavier III", - "Dr. Juan Q. Xavier de la Vega", - "Dr. Juan Q. Xavier de la Vega, Jr.", - "Dr. Juan Q. Xavier de la Vega III", - "de la Vega, Dr. Juan Q. Xavier", - "de la Vega, Dr. Juan Q. Xavier, Jr.", - "de la Vega, Dr. Juan Q. Xavier III", - "Dr. Juan Q. Xavier Velasquez y Garcia", - "Dr. Juan Q. Xavier Velasquez y Garcia, Jr.", - "Dr. Juan Q. Xavier Velasquez y Garcia III", - "Velasquez y Garcia, Dr. Juan Q. Xavier", - "Velasquez y Garcia, Dr. Juan Q. Xavier, Jr.", - "Velasquez y Garcia, Dr. Juan Q. Xavier III", - "John Doe, CLU, CFP, LUTC", - "John P. Doe, CLU, CFP, LUTC", - "Dr. John P. Doe-Ray, CLU, CFP, LUTC", - "Doe-Ray, Dr. John P., CLU, CFP, LUTC", - "Hon. Barrington P. Doe-Ray, Jr.", - "Doe-Ray, Hon. Barrington P. Jr.", - "Doe-Ray, Hon. Barrington P. Jr., CFP, LUTC", - "Jose Aznar y Lopez", - "John E Smith", - "John e Smith", - "John and Jane Smith", - "Rev. John A. Kenneth Doe", - "Donovan McNabb-Smith", - "Rev John A. Kenneth Doe", - "Doe, Rev. John A. Jr.", - "Buca di Beppo", - "Lt. Gen. John A. Kenneth Doe, Jr.", - "Doe, Lt. Gen. John A. Kenneth IV", - "Lt. Gen. John A. Kenneth Doe IV", - 'Mr. and Mrs. John Smith', - 'John Jones (Google Docs)', - 'john e jones', - 'john e jones, III', - 'jones, john e', - 'E.T. Smith', - 'E.T. Smith, II', - 'Smith, E.T., Jr.', - 'A.B. Vajpayee', - 'Rt. Hon. Paul E. Mary', - 'Maid Marion', - 'Amy E. Maid', - 'Jane Doctor', - 'Doctor, Jane E.', - 'dr. ben alex johnson III', - 'Lord of the Universe and Supreme King of the World Lisa Simpson', - 'Benjamin (Ben) Franklin', - 'Benjamin "Ben" Franklin', - "Brian O'connor", - "Sir Gerald", - "Magistrate Judge John F. Forster, Jr", - # "Magistrate Judge Joaquin V.E. Manibusan, Jr", Intials seem to mess this up - "Magistrate-Judge Elizabeth Todd Campbell", - "Mag-Judge Harwell G Davis, III", - "Mag. Judge Byron G. Cudmore", - "Chief Judge J. Leon Holmes", - "Chief Judge Sharon Lovelace Blackburn", - "Judge James M. Moody", - "Judge G. Thomas Eisele", - # "Judge Callie V. S. Granade", - "Judge C Lynwood Smith, Jr", - "Senior Judge Charles R. Butler, Jr", - "Senior Judge Harold D. Vietor", - "Senior Judge Virgil Pittman", - "Honorable Terry F. Moorer", - "Honorable W. Harold Albritton, III", - "Honorable Judge W. Harold Albritton, III", - "Honorable Judge Terry F. Moorer", - "Honorable Judge Susan Russ Walker", - "Hon. Marian W. Payson", - "Hon. Charles J. Siragusa", - "US Magistrate Judge T Michael Putnam", - "Designated Judge David A. Ezra", - "Sr US District Judge Richard G Kopf", - "U.S. District Judge Marc Thomas Treadwell", - "Dra. Andréia da Silva", - "Srta. Andréia da Silva", - -) - - -class HumanNameVariationTests(HumanNameTestBase): - # test automated variations of names in TEST_NAMES. - # Helps test that the 3 code trees work the same - - TEST_NAMES = TEST_NAMES - - def test_variations_of_TEST_NAMES(self) -> None: - for name in self.TEST_NAMES: - hn = HumanName(name) - if len(hn.suffix_list) > 1: - hn = HumanName("{title} {first} {middle} {last} {suffix}".format(**hn.as_dict()).split(',')[0]) - hn.C.empty_attribute_default = '' # format strings below require empty string - hn_dict = hn.as_dict() - nocomma = HumanName("{title} {first} {middle} {last} {suffix}".format(**hn_dict)) - lastnamecomma = HumanName("{last}, {title} {first} {middle} {suffix}".format(**hn_dict)) - if hn.suffix: - suffixcomma = HumanName("{title} {first} {middle} {last}, {suffix}".format(**hn_dict)) - if hn.nickname: - nocomma = HumanName("{title} {first} {middle} {last} {suffix} ({nickname})".format(**hn_dict)) - lastnamecomma = HumanName("{last}, {title} {first} {middle} {suffix} ({nickname})".format(**hn_dict)) - if hn.suffix: - suffixcomma = HumanName("{title} {first} {middle} {last}, {suffix} ({nickname})".format(**hn_dict)) - for attr in hn._members: - self.m(getattr(hn, attr), getattr(nocomma, attr), hn) - self.m(getattr(hn, attr), getattr(lastnamecomma, attr), hn) - if hn.suffix: - self.m(getattr(hn, attr), getattr(suffixcomma, attr), hn) - - -if __name__ == '__main__': - import sys - - if len(sys.argv) > 1: - log.setLevel(logging.ERROR) - log.addHandler(logging.StreamHandler()) - name_string = sys.argv[1] - hn_instance = HumanName(name_string, encoding=sys.stdout.encoding) - print(repr(hn_instance)) - hn_instance.capitalize() - print(repr(hn_instance)) - print("Initials: " + hn_instance.initials()) - else: - print("-"*80) - print("Running tests") - unittest.main(exit=False) - print("-"*80) - print("Running tests with empty_attribute_default = None") - from nameparser.config import CONSTANTS - CONSTANTS.empty_attribute_default = None - unittest.main() diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/base.py b/tests/base.py new file mode 100644 index 0000000..25032e2 --- /dev/null +++ b/tests/base.py @@ -0,0 +1,40 @@ +from typing import Generic, TypeVar + +from nameparser import HumanName + +T = TypeVar('T') + + +class HumanNameTestBase(Generic[T]): + """Shared assert helpers for the parsing tests. + + Formerly subclassed unittest.TestCase. It is now a plain class so pytest can + apply the parametrized dual-run fixture in conftest.py — parametrized + fixtures do not apply to unittest.TestCase subclasses. The assert* methods + are thin shims so existing test bodies move over unchanged. + """ + + def m(self, actual: T, expected: T, hn: HumanName) -> None: + """assertEqual with a better message and awareness of hn.C.empty_attribute_default""" + expected_ = expected or hn.C.empty_attribute_default + try: + assert actual == expected_, "'%s' != '%s' for '%s'\n%r" % ( + actual, + expected, + hn.original, + hn, + ) + except UnicodeDecodeError: + assert actual == expected_ + + def assertEqual(self, first: object, second: object, msg: object = None) -> None: + assert first == second, msg + + def assertTrue(self, expr: object, msg: object = None) -> None: + assert expr, msg + + def assertFalse(self, expr: object, msg: object = None) -> None: + assert not expr, msg + + def assertIn(self, member: object, container: object, msg: object = None) -> None: + assert member in container, msg # type: ignore[operator] diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..7701c13 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,38 @@ +from collections.abc import Iterator + +import pytest + +from nameparser.config import CONSTANTS + +# Scalar (non-collection) config attributes that individual tests mutate on the +# global CONSTANTS singleton. Several tests change these without restoring them; +# the original suite only survived because unittest happens to run methods in +# alphabetical order, so a later test reset the value. pytest runs in definition +# order, so we snapshot and restore these around every test to keep tests +# isolated regardless of order. +_SCALAR_CONFIG_ATTRS = ( + "empty_attribute_default", + "string_format", + "initials_format", + "initials_delimiter", + "capitalize_name", + "force_mixed_case_capitalization", +) + + +@pytest.fixture(autouse=True, params=['', None], ids=['default', 'none']) +def empty_attribute_default(request: pytest.FixtureRequest) -> Iterator[str | None]: + """Run every test under both empty_attribute_default settings, isolating global config. + + Reproduces the original tests.py __main__ block, which ran the whole suite + twice — once with the default ('') and once with None — as a regression + check that the three parsing code paths agree. The surrounding snapshot of + the scalar CONSTANTS attributes restores any global config a test mutates, + so tests do not leak state into one another (the original relied on + unittest's alphabetical method ordering to mask such leaks). + """ + snapshot = {attr: getattr(CONSTANTS, attr) for attr in _SCALAR_CONFIG_ATTRS} + CONSTANTS.empty_attribute_default = request.param + yield request.param + for attr, value in snapshot.items(): + setattr(CONSTANTS, attr, value) diff --git a/tests/test_brute_force.py b/tests/test_brute_force.py new file mode 100644 index 0000000..c46e81f --- /dev/null +++ b/tests/test_brute_force.py @@ -0,0 +1,808 @@ +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +class HumanNameBruteForceTests(HumanNameTestBase): + + def test1(self) -> None: + hn = HumanName("John Doe") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + + def test2(self) -> None: + hn = HumanName("John Doe, Jr.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "Jr.", hn) + + def test3(self) -> None: + hn = HumanName("John Doe III") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "III", hn) + + def test4(self) -> None: + hn = HumanName("Doe, John") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + + def test5(self) -> None: + hn = HumanName("Doe, John, Jr.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "Jr.", hn) + + def test6(self) -> None: + hn = HumanName("Doe, John III") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "III", hn) + + def test7(self) -> None: + hn = HumanName("John A. Doe") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + + def test8(self) -> None: + hn = HumanName("John A. Doe, Jr") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + self.m(hn.suffix, "Jr", hn) + + def test9(self) -> None: + hn = HumanName("John A. Doe III") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + self.m(hn.suffix, "III", hn) + + def test10(self) -> None: + hn = HumanName("Doe, John A.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + + def test11(self) -> None: + hn = HumanName("Doe, John A., Jr.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + self.m(hn.suffix, "Jr.", hn) + + def test12(self) -> None: + hn = HumanName("Doe, John A., III") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + self.m(hn.suffix, "III", hn) + + def test13(self) -> None: + hn = HumanName("John A. Kenneth Doe") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + + def test14(self) -> None: + hn = HumanName("John A. Kenneth Doe, Jr.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.suffix, "Jr.", hn) + + def test15(self) -> None: + hn = HumanName("John A. Kenneth Doe III") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.suffix, "III", hn) + + def test16(self) -> None: + hn = HumanName("Doe, John. A. Kenneth") + self.m(hn.first, "John.", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + + def test17(self) -> None: + hn = HumanName("Doe, John. A. Kenneth, Jr.") + self.m(hn.first, "John.", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.suffix, "Jr.", hn) + + def test18(self) -> None: + hn = HumanName("Doe, John. A. Kenneth III") + self.m(hn.first, "John.", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.suffix, "III", hn) + + def test19(self) -> None: + hn = HumanName("Dr. John Doe") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.title, "Dr.", hn) + + def test20(self) -> None: + hn = HumanName("Dr. John Doe, Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "Jr.", hn) + + def test21(self) -> None: + hn = HumanName("Dr. John Doe III") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "III", hn) + + def test22(self) -> None: + hn = HumanName("Doe, Dr. John") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + + def test23(self) -> None: + hn = HumanName("Doe, Dr. John, Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "Jr.", hn) + + def test24(self) -> None: + hn = HumanName("Doe, Dr. John III") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "III", hn) + + def test25(self) -> None: + hn = HumanName("Dr. John A. Doe") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + + def test26(self) -> None: + hn = HumanName("Dr. John A. Doe, Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + self.m(hn.suffix, "Jr.", hn) + + def test27(self) -> None: + hn = HumanName("Dr. John A. Doe III") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + self.m(hn.suffix, "III", hn) + + def test28(self) -> None: + hn = HumanName("Doe, Dr. John A.") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + + def test29(self) -> None: + hn = HumanName("Doe, Dr. John A. Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + self.m(hn.suffix, "Jr.", hn) + + def test30(self) -> None: + hn = HumanName("Doe, Dr. John A. III") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "A.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "III", hn) + + def test31(self) -> None: + hn = HumanName("Dr. John A. Kenneth Doe") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + + def test32(self) -> None: + hn = HumanName("Dr. John A. Kenneth Doe, Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "Jr.", hn) + + def test33(self) -> None: + hn = HumanName("Al Arnold Gore, Jr.") + self.m(hn.middle, "Arnold", hn) + self.m(hn.first, "Al", hn) + self.m(hn.last, "Gore", hn) + self.m(hn.suffix, "Jr.", hn) + + def test34(self) -> None: + hn = HumanName("Dr. John A. Kenneth Doe III") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "III", hn) + + def test35(self) -> None: + hn = HumanName("Doe, Dr. John A. Kenneth") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + + def test36(self) -> None: + hn = HumanName("Doe, Dr. John A. Kenneth Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "Jr.", hn) + + def test37(self) -> None: + hn = HumanName("Doe, Dr. John A. Kenneth III") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "III", hn) + + def test38(self) -> None: + hn = HumanName("Juan de la Vega") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + + def test39(self) -> None: + hn = HumanName("Juan de la Vega, Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.suffix, "Jr.", hn) + + def test40(self) -> None: + hn = HumanName("Juan de la Vega III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.suffix, "III", hn) + + def test41(self) -> None: + hn = HumanName("de la Vega, Juan") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + + def test42(self) -> None: + hn = HumanName("de la Vega, Juan, Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.suffix, "Jr.", hn) + + def test43(self) -> None: + hn = HumanName("de la Vega, Juan III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.suffix, "III", hn) + + def test44(self) -> None: + hn = HumanName("Juan Velasquez y Garcia") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test45(self) -> None: + hn = HumanName("Juan Velasquez y Garcia, Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test46(self) -> None: + hn = HumanName("Juan Velasquez y Garcia III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test47(self) -> None: + hn = HumanName("Velasquez y Garcia, Juan") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test48(self) -> None: + hn = HumanName("Velasquez y Garcia, Juan, Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test49(self) -> None: + hn = HumanName("Velasquez y Garcia, Juan III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test50(self) -> None: + hn = HumanName("Dr. Juan de la Vega") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + + def test51(self) -> None: + hn = HumanName("Dr. Juan de la Vega, Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.suffix, "Jr.", hn) + + def test52(self) -> None: + hn = HumanName("Dr. Juan de la Vega III") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.suffix, "III", hn) + + def test53(self) -> None: + hn = HumanName("de la Vega, Dr. Juan") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + + def test54(self) -> None: + hn = HumanName("de la Vega, Dr. Juan, Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.suffix, "Jr.", hn) + + def test55(self) -> None: + hn = HumanName("de la Vega, Dr. Juan III") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.suffix, "III", hn) + + def test56(self) -> None: + hn = HumanName("Dr. Juan Velasquez y Garcia") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test57(self) -> None: + hn = HumanName("Dr. Juan Velasquez y Garcia, Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test58(self) -> None: + hn = HumanName("Dr. Juan Velasquez y Garcia III") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test59(self) -> None: + hn = HumanName("Velasquez y Garcia, Dr. Juan") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test60(self) -> None: + hn = HumanName("Velasquez y Garcia, Dr. Juan, Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test61(self) -> None: + hn = HumanName("Velasquez y Garcia, Dr. Juan III") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test62(self) -> None: + hn = HumanName("Juan Q. de la Vega") + self.m(hn.first, "Juan", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.last, "de la Vega", hn) + + def test63(self) -> None: + hn = HumanName("Juan Q. de la Vega, Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.suffix, "Jr.", hn) + + def test64(self) -> None: + hn = HumanName("Juan Q. de la Vega III") + self.m(hn.first, "Juan", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.suffix, "III", hn) + + def test65(self) -> None: + hn = HumanName("de la Vega, Juan Q.") + self.m(hn.first, "Juan", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.last, "de la Vega", hn) + + def test66(self) -> None: + hn = HumanName("de la Vega, Juan Q., Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.suffix, "Jr.", hn) + + def test67(self) -> None: + hn = HumanName("de la Vega, Juan Q. III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.suffix, "III", hn) + + def test68(self) -> None: + hn = HumanName("Juan Q. Velasquez y Garcia") + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test69(self) -> None: + hn = HumanName("Juan Q. Velasquez y Garcia, Jr.") + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test70(self) -> None: + hn = HumanName("Juan Q. Velasquez y Garcia III") + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test71(self) -> None: + hn = HumanName("Velasquez y Garcia, Juan Q.") + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test72(self) -> None: + hn = HumanName("Velasquez y Garcia, Juan Q., Jr.") + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test73(self) -> None: + hn = HumanName("Velasquez y Garcia, Juan Q. III") + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test74(self) -> None: + hn = HumanName("Dr. Juan Q. de la Vega") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.last, "de la Vega", hn) + + def test75(self) -> None: + hn = HumanName("Dr. Juan Q. de la Vega, Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.suffix, "Jr.", hn) + + def test76(self) -> None: + hn = HumanName("Dr. Juan Q. de la Vega III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.suffix, "III", hn) + + def test77(self) -> None: + hn = HumanName("de la Vega, Dr. Juan Q.") + self.m(hn.first, "Juan", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.title, "Dr.", hn) + + def test78(self) -> None: + hn = HumanName("de la Vega, Dr. Juan Q., Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.suffix, "Jr.", hn) + self.m(hn.title, "Dr.", hn) + + def test79(self) -> None: + hn = HumanName("de la Vega, Dr. Juan Q. III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.suffix, "III", hn) + self.m(hn.title, "Dr.", hn) + + def test80(self) -> None: + hn = HumanName("Dr. Juan Q. Velasquez y Garcia") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test81(self) -> None: + hn = HumanName("Dr. Juan Q. Velasquez y Garcia, Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test82(self) -> None: + hn = HumanName("Dr. Juan Q. Velasquez y Garcia III") + self.m(hn.middle, "Q.", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test83(self) -> None: + hn = HumanName("Velasquez y Garcia, Dr. Juan Q.") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test84(self) -> None: + hn = HumanName("Velasquez y Garcia, Dr. Juan Q., Jr.") + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test85(self) -> None: + hn = HumanName("Velasquez y Garcia, Dr. Juan Q. III") + self.m(hn.middle, "Q.", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test86(self) -> None: + hn = HumanName("Juan Q. Xavier de la Vega") + self.m(hn.first, "Juan", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.last, "de la Vega", hn) + + def test87(self) -> None: + hn = HumanName("Juan Q. Xavier de la Vega, Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "Jr.", hn) + + def test88(self) -> None: + hn = HumanName("Juan Q. Xavier de la Vega III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "III", hn) + + def test89(self) -> None: + hn = HumanName("de la Vega, Juan Q. Xavier") + self.m(hn.first, "Juan", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.last, "de la Vega", hn) + + def test90(self) -> None: + hn = HumanName("de la Vega, Juan Q. Xavier, Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "Jr.", hn) + + def test91(self) -> None: + hn = HumanName("de la Vega, Juan Q. Xavier III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "III", hn) + + def test92(self) -> None: + hn = HumanName("Dr. Juan Q. Xavier de la Vega") + self.m(hn.first, "Juan", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.last, "de la Vega", hn) + + def test93(self) -> None: + hn = HumanName("Dr. Juan Q. Xavier de la Vega, Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "Jr.", hn) + + def test94(self) -> None: + hn = HumanName("Dr. Juan Q. Xavier de la Vega III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "III", hn) + + def test95(self) -> None: + hn = HumanName("de la Vega, Dr. Juan Q. Xavier") + self.m(hn.first, "Juan", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.last, "de la Vega", hn) + + def test96(self) -> None: + hn = HumanName("de la Vega, Dr. Juan Q. Xavier, Jr.") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "Jr.", hn) + + def test97(self) -> None: + hn = HumanName("de la Vega, Dr. Juan Q. Xavier III") + self.m(hn.first, "Juan", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.last, "de la Vega", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "III", hn) + + def test98(self) -> None: + hn = HumanName("Juan Q. Xavier Velasquez y Garcia") + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test99(self) -> None: + hn = HumanName("Juan Q. Xavier Velasquez y Garcia, Jr.") + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test100(self) -> None: + hn = HumanName("Juan Q. Xavier Velasquez y Garcia III") + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test101(self) -> None: + hn = HumanName("Velasquez y Garcia, Juan Q. Xavier") + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test102(self) -> None: + hn = HumanName("Velasquez y Garcia, Juan Q. Xavier, Jr.") + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test103(self) -> None: + hn = HumanName("Velasquez y Garcia, Juan Q. Xavier III") + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test104(self) -> None: + hn = HumanName("Dr. Juan Q. Xavier Velasquez y Garcia") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test105(self) -> None: + hn = HumanName("Dr. Juan Q. Xavier Velasquez y Garcia, Jr.") + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test106(self) -> None: + hn = HumanName("Dr. Juan Q. Xavier Velasquez y Garcia III") + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test107(self) -> None: + hn = HumanName("Velasquez y Garcia, Dr. Juan Q. Xavier") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + + def test108(self) -> None: + hn = HumanName("Velasquez y Garcia, Dr. Juan Q. Xavier, Jr.") + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "Jr.", hn) + + def test109(self) -> None: + hn = HumanName("Velasquez y Garcia, Dr. Juan Q. Xavier III") + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.first, "Juan", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test110(self) -> None: + hn = HumanName("John Doe, CLU, CFP, LUTC") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "CLU, CFP, LUTC", hn) + + def test111(self) -> None: + hn = HumanName("John P. Doe, CLU, CFP, LUTC") + self.m(hn.first, "John", hn) + self.m(hn.middle, "P.", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "CLU, CFP, LUTC", hn) + + def test112(self) -> None: + hn = HumanName("Dr. John P. Doe-Ray, CLU, CFP, LUTC") + self.m(hn.first, "John", hn) + self.m(hn.middle, "P.", hn) + self.m(hn.last, "Doe-Ray", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.suffix, "CLU, CFP, LUTC", hn) + + def test113(self) -> None: + hn = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "P.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe-Ray", hn) + self.m(hn.suffix, "CLU, CFP, LUTC", hn) + + def test115(self) -> None: + hn = HumanName("Hon. Barrington P. Doe-Ray, Jr.") + self.m(hn.title, "Hon.", hn) + self.m(hn.middle, "P.", hn) + self.m(hn.first, "Barrington", hn) + self.m(hn.last, "Doe-Ray", hn) + + def test116(self) -> None: + hn = HumanName("Doe-Ray, Hon. Barrington P. Jr., CFP, LUTC") + self.m(hn.title, "Hon.", hn) + self.m(hn.middle, "P.", hn) + self.m(hn.first, "Barrington", hn) + self.m(hn.last, "Doe-Ray", hn) + self.m(hn.suffix, "Jr., CFP, LUTC", hn) + + def test117(self) -> None: + hn = HumanName("Rt. Hon. Paul E. Mary") + self.m(hn.title, "Rt. Hon.", hn) + self.m(hn.first, "Paul", hn) + self.m(hn.middle, "E.", hn) + self.m(hn.last, "Mary", hn) + + def test119(self) -> None: + hn = HumanName("Lord God Almighty") + self.m(hn.title, "Lord", hn) + self.m(hn.first, "God", hn) + self.m(hn.last, "Almighty", hn) diff --git a/tests/test_capitalization.py b/tests/test_capitalization.py new file mode 100644 index 0000000..a281b81 --- /dev/null +++ b/tests/test_capitalization.py @@ -0,0 +1,84 @@ +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +class HumanNameCapitalizationTestCase(HumanNameTestBase): + def test_capitalization_exception_for_III(self) -> None: + hn = HumanName('juan q. xavier velasquez y garcia iii') + hn.capitalize() + self.m(str(hn), 'Juan Q. Xavier Velasquez y Garcia III', hn) + + # FIXME: this test does not pass due to a known issue + # http://code.google.com/p/python-nameparser/issues/detail?id=22 + @pytest.mark.xfail + def test_capitalization_exception_for_already_capitalized_III_KNOWN_FAILURE(self) -> None: + hn = HumanName('juan garcia III') + hn.capitalize() + self.m(str(hn), 'Juan Garcia III', hn) + + def test_capitalize_title(self) -> None: + hn = HumanName('lt. gen. john a. kenneth doe iv') + hn.capitalize() + self.m(str(hn), 'Lt. Gen. John A. Kenneth Doe IV', hn) + + def test_capitalize_title_to_lower(self) -> None: + hn = HumanName('LT. GEN. JOHN A. KENNETH DOE IV') + hn.capitalize() + self.m(str(hn), 'Lt. Gen. John A. Kenneth Doe IV', hn) + + # Capitalization with M(a)c and hyphenated names + def test_capitalization_with_Mac_as_hyphenated_names(self) -> None: + hn = HumanName('donovan mcnabb-smith') + hn.capitalize() + self.m(str(hn), 'Donovan McNabb-Smith', hn) + + def test_capitization_middle_initial_is_also_a_conjunction(self) -> None: + hn = HumanName('scott e. werner') + hn.capitalize() + self.m(str(hn), 'Scott E. Werner', hn) + + # Leaving already-capitalized names alone + def test_no_change_to_mixed_chase(self) -> None: + hn = HumanName('Shirley Maclaine') + hn.capitalize() + self.m(str(hn), 'Shirley Maclaine', hn) + + def test_force_capitalization(self) -> None: + hn = HumanName('Shirley Maclaine') + hn.capitalize(force=True) + self.m(str(hn), 'Shirley MacLaine', hn) + + def test_capitalize_diacritics(self) -> None: + hn = HumanName('matthëus schmidt') + hn.capitalize() + self.m(str(hn), 'Matthëus Schmidt', hn) + + # http://code.google.com/p/python-nameparser/issues/detail?id=15 + def test_downcasing_mac(self) -> None: + hn = HumanName('RONALD MACDONALD') + hn.capitalize() + self.m(str(hn), 'Ronald MacDonald', hn) + + # http://code.google.com/p/python-nameparser/issues/detail?id=23 + def test_downcasing_mc(self) -> None: + hn = HumanName('RONALD MCDONALD') + hn.capitalize() + self.m(str(hn), 'Ronald McDonald', hn) + + def test_short_names_with_mac(self) -> None: + hn = HumanName('mack johnson') + hn.capitalize() + self.m(str(hn), 'Mack Johnson', hn) + + def test_portuguese_prefixes(self) -> None: + hn = HumanName("joao da silva do amaral de souza") + hn.capitalize() + self.m(str(hn), 'Joao da Silva do Amaral de Souza', hn) + + def test_capitalize_prefix_clash_on_first_name(self) -> None: + hn = HumanName("van nguyen") + hn.capitalize() + self.m(str(hn), 'Van Nguyen', hn) diff --git a/tests/test_conjunctions.py b/tests/test_conjunctions.py new file mode 100644 index 0000000..73ee3cc --- /dev/null +++ b/tests/test_conjunctions.py @@ -0,0 +1,203 @@ +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +class HumanNameConjunctionTestCase(HumanNameTestBase): + # Last name with conjunction + def test_last_name_with_conjunction(self) -> None: + hn = HumanName('Jose Aznar y Lopez') + self.m(hn.first, "Jose", hn) + self.m(hn.last, "Aznar y Lopez", hn) + + def test_multiple_conjunctions(self) -> None: + hn = HumanName("part1 of The part2 of the part3 and part4") + self.m(hn.first, "part1 of The part2 of the part3 and part4", hn) + + def test_multiple_conjunctions2(self) -> None: + hn = HumanName("part1 of and The part2 of the part3 And part4") + self.m(hn.first, "part1 of and The part2 of the part3 And part4", hn) + + def test_ends_with_conjunction(self) -> None: + hn = HumanName("Jon Dough and") + self.m(hn.first, "Jon", hn) + self.m(hn.last, "Dough and", hn) + + def test_ends_with_two_conjunctions(self) -> None: + hn = HumanName("Jon Dough and of") + self.m(hn.first, "Jon", hn) + self.m(hn.last, "Dough and of", hn) + + def test_starts_with_conjunction(self) -> None: + hn = HumanName("and Jon Dough") + self.m(hn.first, "and Jon", hn) + self.m(hn.last, "Dough", hn) + + def test_starts_with_two_conjunctions(self) -> None: + hn = HumanName("the and Jon Dough") + self.m(hn.first, "the and Jon", hn) + self.m(hn.last, "Dough", hn) + + # Potential conjunction/prefix treated as initial (because uppercase) + def test_uppercase_middle_initial_conflict_with_conjunction(self) -> None: + hn = HumanName('John E Smith') + self.m(hn.first, "John", hn) + self.m(hn.middle, "E", hn) + self.m(hn.last, "Smith", hn) + + def test_lowercase_middle_initial_with_period_conflict_with_conjunction(self) -> None: + hn = HumanName('john e. smith') + self.m(hn.first, "john", hn) + self.m(hn.middle, "e.", hn) + self.m(hn.last, "smith", hn) + + # The conjunction "e" can also be an initial + def test_lowercase_first_initial_conflict_with_conjunction(self) -> None: + hn = HumanName('e j smith') + self.m(hn.first, "e", hn) + self.m(hn.middle, "j", hn) + self.m(hn.last, "smith", hn) + + def test_lowercase_middle_initial_conflict_with_conjunction(self) -> None: + hn = HumanName('John e Smith') + self.m(hn.first, "John", hn) + self.m(hn.middle, "e", hn) + self.m(hn.last, "Smith", hn) + + def test_lowercase_middle_initial_and_suffix_conflict_with_conjunction(self) -> None: + hn = HumanName('John e Smith, III') + self.m(hn.first, "John", hn) + self.m(hn.middle, "e", hn) + self.m(hn.last, "Smith", hn) + self.m(hn.suffix, "III", hn) + + def test_lowercase_middle_initial_and_nocomma_suffix_conflict_with_conjunction(self) -> None: + hn = HumanName('John e Smith III') + self.m(hn.first, "John", hn) + self.m(hn.middle, "e", hn) + self.m(hn.last, "Smith", hn) + self.m(hn.suffix, "III", hn) + + def test_lowercase_middle_initial_comma_lastname_and_suffix_conflict_with_conjunction(self) -> None: + hn = HumanName('Smith, John e, III, Jr') + self.m(hn.first, "John", hn) + self.m(hn.middle, "e", hn) + self.m(hn.last, "Smith", hn) + self.m(hn.suffix, "III, Jr", hn) + + @pytest.mark.xfail + def test_two_initials_conflict_with_conjunction(self) -> None: + # Supporting this seems to screw up titles with periods in them like M.B.A. + hn = HumanName('E.T. Smith') + self.m(hn.first, "E.", hn) + self.m(hn.middle, "T.", hn) + self.m(hn.last, "Smith", hn) + + def test_couples_names(self) -> None: + hn = HumanName('John and Jane Smith') + self.m(hn.first, "John and Jane", hn) + self.m(hn.last, "Smith", hn) + + def test_couples_names_with_conjunction_lastname(self) -> None: + hn = HumanName('John and Jane Aznar y Lopez') + self.m(hn.first, "John and Jane", hn) + self.m(hn.last, "Aznar y Lopez", hn) + + def test_couple_titles(self) -> None: + hn = HumanName('Mr. and Mrs. John and Jane Smith') + self.m(hn.title, "Mr. and Mrs.", hn) + self.m(hn.first, "John and Jane", hn) + self.m(hn.last, "Smith", hn) + + def test_title_with_three_part_name_last_initial_is_suffix_uppercase_no_period(self) -> None: + hn = HumanName("King John Alexander V") + self.m(hn.title, "King", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Alexander", hn) + self.m(hn.suffix, "V", hn) + + def test_four_name_parts_with_suffix_that_could_be_initial_lowercase_no_period(self) -> None: + hn = HumanName("larry james edward johnson v") + self.m(hn.first, "larry", hn) + self.m(hn.middle, "james edward", hn) + self.m(hn.last, "johnson", hn) + self.m(hn.suffix, "v", hn) + + def test_four_name_parts_with_suffix_that_could_be_initial_uppercase_no_period(self) -> None: + hn = HumanName("Larry James Johnson I") + self.m(hn.first, "Larry", hn) + self.m(hn.middle, "James", hn) + self.m(hn.last, "Johnson", hn) + self.m(hn.suffix, "I", hn) + + def test_roman_numeral_initials(self) -> None: + hn = HumanName("Larry V I") + self.m(hn.first, "Larry", hn) + self.m(hn.middle, "V", hn) + self.m(hn.last, "I", hn) + self.m(hn.suffix, "", hn) + + def test_roman_numeral_suffix_not_in_suffix_list(self) -> None: + # VI-X are not in the suffix word lists, so they reach the + # is_roman_numeral(nxt) branch rather than are_suffixes() + hn = HumanName("John Smith VI") + self.m(hn.first, "John", hn) + self.m(hn.last, "Smith", hn) + self.m(hn.suffix, "VI", hn) + + # tests for Rev. title (Reverend) + def test124(self) -> None: + hn = HumanName("Rev. John A. Kenneth Doe") + self.m(hn.title, "Rev.", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + + def test125(self) -> None: + hn = HumanName("Rev John A. Kenneth Doe") + self.m(hn.title, "Rev", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + + def test126(self) -> None: + hn = HumanName("Doe, Rev. John A. Jr.") + self.m(hn.title, "Rev.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + self.m(hn.suffix, "Jr.", hn) + + def test127(self) -> None: + hn = HumanName("Buca di Beppo") + self.m(hn.first, "Buca", hn) + self.m(hn.last, "di Beppo", hn) + + def test_le_as_last_name(self) -> None: + hn = HumanName("Yin Le") + self.m(hn.first, "Yin", hn) + self.m(hn.last, "Le", hn) + + def test_le_as_last_name_with_middle_initial(self) -> None: + hn = HumanName("Yin a Le") + self.m(hn.first, "Yin", hn) + self.m(hn.middle, "a", hn) + self.m(hn.last, "Le", hn) + + def test_conjunction_in_an_address_with_a_title(self) -> None: + hn = HumanName("His Excellency Lord Duncan") + self.m(hn.title, "His Excellency Lord", hn) + self.m(hn.last, "Duncan", hn) + + @pytest.mark.xfail + def test_conjunction_in_an_address_with_a_first_name_title(self) -> None: + hn = HumanName("Her Majesty Queen Elizabeth") + self.m(hn.title, "Her Majesty Queen", hn) + # if you want to be technical, Queen is in FIRST_NAME_TITLES + self.m(hn.first, "Elizabeth", hn) + + def test_name_is_conjunctions(self) -> None: + hn = HumanName("e and e") + self.m(hn.first, "e and e", hn) diff --git a/tests/test_constants.py b/tests/test_constants.py new file mode 100644 index 0000000..0d6912e --- /dev/null +++ b/tests/test_constants.py @@ -0,0 +1,106 @@ +from nameparser import HumanName +from nameparser.config import Constants + +from tests.base import HumanNameTestBase + + +class ConstantsCustomizationTests(HumanNameTestBase): + + def test_add_title(self) -> None: + hn = HumanName("Te Awanui-a-Rangi Black", constants=None) + start_len = len(hn.C.titles) + self.assertTrue(start_len > 0) + hn.C.titles.add('te') + self.assertEqual(start_len + 1, len(hn.C.titles)) + hn.parse_full_name() + self.m(hn.title, "Te", hn) + self.m(hn.first, "Awanui-a-Rangi", hn) + self.m(hn.last, "Black", hn) + + def test_remove_title(self) -> None: + hn = HumanName("Hon Solo", constants=None) + start_len = len(hn.C.titles) + self.assertTrue(start_len > 0) + hn.C.titles.remove('hon') + self.assertEqual(start_len - 1, len(hn.C.titles)) + hn.parse_full_name() + self.m(hn.first, "Hon", hn) + self.m(hn.last, "Solo", hn) + + def test_add_multiple_arguments(self) -> None: + hn = HumanName("Assoc Dean of Chemistry Robert Johns", constants=None) + hn.C.titles.add('dean', 'Chemistry') + hn.parse_full_name() + self.m(hn.title, "Assoc Dean of Chemistry", hn) + self.m(hn.first, "Robert", hn) + self.m(hn.last, "Johns", hn) + + def test_instances_can_have_own_constants(self) -> None: + hn = HumanName("", None) + hn2 = HumanName("") + hn.C.titles.remove('hon') + self.assertEqual('hon' in hn.C.titles, False) + self.assertEqual(hn.has_own_config, True) + self.assertEqual('hon' in hn2.C.titles, True) + self.assertEqual(hn2.has_own_config, False) + + def test_can_change_global_constants(self) -> None: + hn = HumanName("") + hn2 = HumanName("") + hn.C.titles.remove('hon') + self.assertEqual('hon' in hn.C.titles, False) + self.assertEqual('hon' in hn2.C.titles, False) + self.assertEqual(hn.has_own_config, False) + self.assertEqual(hn2.has_own_config, False) + # clean up so we don't mess up other tests + hn.C.titles.add('hon') + + def test_remove_multiple_arguments(self) -> None: + hn = HumanName("Ms Hon Solo", constants=None) + hn.C.titles.remove('hon', 'ms') + hn.parse_full_name() + self.m(hn.first, "Ms", hn) + self.m(hn.middle, "Hon", hn) + self.m(hn.last, "Solo", hn) + + def test_chain_multiple_arguments(self) -> None: + hn = HumanName("Dean Ms Hon Solo", constants=None) + hn.C.titles.remove('hon', 'ms').add('dean') + hn.parse_full_name() + self.m(hn.title, "Dean", hn) + self.m(hn.first, "Ms", hn) + self.m(hn.middle, "Hon", hn) + self.m(hn.last, "Solo", hn) + + def test_empty_attribute_default(self) -> None: + from nameparser.config import CONSTANTS + _orig = CONSTANTS.empty_attribute_default + CONSTANTS.empty_attribute_default = None + hn = HumanName("") + self.m(hn.title, None, hn) + self.m(hn.first, None, hn) + self.m(hn.middle, None, hn) + self.m(hn.last, None, hn) + self.m(hn.suffix, None, hn) + self.m(hn.nickname, None, hn) + CONSTANTS.empty_attribute_default = _orig + + def test_empty_attribute_on_instance(self) -> None: + hn = HumanName("", None) + hn.C.empty_attribute_default = None + self.m(hn.title, None, hn) + self.m(hn.first, None, hn) + self.m(hn.middle, None, hn) + self.m(hn.last, None, hn) + self.m(hn.suffix, None, hn) + self.m(hn.nickname, None, hn) + + def test_none_empty_attribute_string_formatting(self) -> None: + hn = HumanName("", None) + hn.C.empty_attribute_default = None + self.assertEqual('', str(hn), hn) + + def test_add_constant_with_explicit_encoding(self) -> None: + c = Constants() + c.titles.add_with_encoding(b'b\351ck', encoding='latin_1') + self.assertIn('béck', c.titles) diff --git a/tests/test_first_name.py b/tests/test_first_name.py new file mode 100644 index 0000000..0058acc --- /dev/null +++ b/tests/test_first_name.py @@ -0,0 +1,69 @@ +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +class FirstNameHandlingTests(HumanNameTestBase): + def test_first_name(self) -> None: + hn = HumanName("Andrew") + self.m(hn.first, "Andrew", hn) + + def test_assume_title_and_one_other_name_is_last_name(self) -> None: + hn = HumanName("Rev Andrews") + self.m(hn.title, "Rev", hn) + self.m(hn.last, "Andrews", hn) + + # TODO: Seems "Andrews, M.D.", Andrews should be treated as a last name + # but other suffixes like "George Jr." should be first names. Might be + # related to https://github.com/derek73/python-nameparser/issues/2 + @pytest.mark.xfail + def test_assume_suffix_title_and_one_other_name_is_last_name(self) -> None: + hn = HumanName("Andrews, M.D.") + self.m(hn.suffix, "M.D.", hn) + self.m(hn.last, "Andrews", hn) + + def test_suffix_in_lastname_part_of_lastname_comma_format(self) -> None: + hn = HumanName("Smith Jr., John") + self.m(hn.last, "Smith", hn) + self.m(hn.first, "John", hn) + self.m(hn.suffix, "Jr.", hn) + + def test_sir_exception_to_first_name_rule(self) -> None: + hn = HumanName("Sir Gerald") + self.m(hn.title, "Sir", hn) + self.m(hn.first, "Gerald", hn) + + def test_king_exception_to_first_name_rule(self) -> None: + hn = HumanName("King Henry") + self.m(hn.title, "King", hn) + self.m(hn.first, "Henry", hn) + + def test_queen_exception_to_first_name_rule(self) -> None: + hn = HumanName("Queen Elizabeth") + self.m(hn.title, "Queen", hn) + self.m(hn.first, "Elizabeth", hn) + + def test_dame_exception_to_first_name_rule(self) -> None: + hn = HumanName("Dame Mary") + self.m(hn.title, "Dame", hn) + self.m(hn.first, "Mary", hn) + + def test_first_name_is_not_prefix_if_only_two_parts(self) -> None: + """When there are only two parts, don't join prefixes or conjunctions""" + hn = HumanName("Van Nguyen") + self.m(hn.first, "Van", hn) + self.m(hn.last, "Nguyen", hn) + + def test_first_name_is_not_prefix_if_only_two_parts_comma(self) -> None: + hn = HumanName("Nguyen, Van") + self.m(hn.first, "Van", hn) + self.m(hn.last, "Nguyen", hn) + + @pytest.mark.xfail + def test_first_name_is_prefix_if_three_parts(self) -> None: + """Not sure how to fix this without breaking Mr and Mrs""" + hn = HumanName("Mr. Van Nguyen") + self.m(hn.first, "Van", hn) + self.m(hn.last, "Nguyen", hn) diff --git a/tests/test_initials.py b/tests/test_initials.py new file mode 100644 index 0000000..b87f64c --- /dev/null +++ b/tests/test_initials.py @@ -0,0 +1,111 @@ +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +class InitialsTestCase(HumanNameTestBase): + def test_initials(self) -> None: + hn = HumanName("Andrew Boris Petersen") + self.m(hn.initials(), "A. B. P.", hn) + + def test_initials_simple_name(self) -> None: + hn = HumanName("John Doe") + self.m(hn.initials(), "J. D.", hn) + hn = HumanName("John Doe", initials_format="{first} {last}") + self.m(hn.initials(), "J. D.", hn) + hn = HumanName("John Doe", initials_format="{last}") + self.m(hn.initials(), "D.", hn) + hn = HumanName("John Doe", initials_format="{first}") + self.m(hn.initials(), "J.", hn) + hn = HumanName("John Doe", initials_format="{middle}") + self.m(hn.initials(), "", hn) + + def test_initials_complex_name(self) -> None: + hn = HumanName("Doe, John A. Kenneth, Jr.") + self.m(hn.initials(), "J. A. K. D.", hn) + + def test_initials_format(self) -> None: + hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{first} {middle}") + self.m(hn.initials(), "J. A. K.", hn) + hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{first} {last}") + self.m(hn.initials(), "J. D.", hn) + hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{middle} {last}") + self.m(hn.initials(), "A. K. D.", hn) + hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{first}, {last}") + self.m(hn.initials(), "J., D.", hn) + + def test_initials_format_constants(self) -> None: + from nameparser.config import CONSTANTS + _orig = CONSTANTS.initials_format + CONSTANTS.initials_format = "{first} {last}" + hn = HumanName("Doe, John A. Kenneth, Jr.") + self.m(hn.initials(), "J. D.", hn) + CONSTANTS.initials_format = "{first} {last}" + hn = HumanName("Doe, John A. Kenneth, Jr.") + self.m(hn.initials(), "J. D.", hn) + CONSTANTS.initials_format = _orig + + def test_initials_delimiter(self) -> None: + hn = HumanName("Doe, John A. Kenneth, Jr.", initials_delimiter=";") + self.m(hn.initials(), "J; A; K; D;", hn) + + def test_initials_delimiter_constants(self) -> None: + from nameparser.config import CONSTANTS + _orig = CONSTANTS.initials_delimiter + CONSTANTS.initials_delimiter = ";" + hn = HumanName("Doe, John A. Kenneth, Jr.") + self.m(hn.initials(), "J; A; K; D;", hn) + CONSTANTS.initials_delimiter = _orig + + def test_initials_list(self) -> None: + hn = HumanName("Andrew Boris Petersen") + self.m(hn.initials_list(), ["A", "B", "P"], hn) + + def test_initials_list_complex_name(self) -> None: + hn = HumanName("Doe, John A. Kenneth, Jr.") + self.m(hn.initials_list(), ["J", "A", "K", "D"], hn) + + def test_initials_with_prefix_firstname(self) -> None: + hn = HumanName("Van Jeremy Johnson") + self.m(hn.initials_list(), ["V", "J", "J"], hn) + + def test_initials_with_prefix(self) -> None: + hn = HumanName("Alex van Johnson") + self.m(hn.initials_list(), ["A", "J"], hn) + + def test_constructor_first(self) -> None: + hn = HumanName(first="TheName") + self.assertFalse(hn.unparsable) + self.m(hn.first, "TheName", hn) + + def test_constructor_middle(self) -> None: + hn = HumanName(middle="TheName") + self.assertFalse(hn.unparsable) + self.m(hn.middle, "TheName", hn) + + def test_constructor_last(self) -> None: + hn = HumanName(last="TheName") + self.assertFalse(hn.unparsable) + self.m(hn.last, "TheName", hn) + + def test_constructor_title(self) -> None: + hn = HumanName(title="TheName") + self.assertFalse(hn.unparsable) + self.m(hn.title, "TheName", hn) + + def test_constructor_suffix(self) -> None: + hn = HumanName(suffix="TheName") + self.assertFalse(hn.unparsable) + self.m(hn.suffix, "TheName", hn) + + def test_constructor_nickname(self) -> None: + hn = HumanName(nickname="TheName") + self.assertFalse(hn.unparsable) + self.m(hn.nickname, "TheName", hn) + + def test_constructor_multiple(self) -> None: + hn = HumanName(first="TheName", last="lastname", title="mytitle", full_name="donotparse") + self.assertFalse(hn.unparsable) + self.m(hn.first, "TheName", hn) + self.m(hn.last, "lastname", hn) + self.m(hn.title, "mytitle", hn) diff --git a/tests/test_nicknames.py b/tests/test_nicknames.py new file mode 100644 index 0000000..c5aea85 --- /dev/null +++ b/tests/test_nicknames.py @@ -0,0 +1,176 @@ +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +class NicknameTestCase(HumanNameTestBase): + # https://code.google.com/p/python-nameparser/issues/detail?id=33 + def test_nickname_in_parenthesis(self) -> None: + hn = HumanName("Benjamin (Ben) Franklin") + self.m(hn.first, "Benjamin", hn) + self.m(hn.middle, "", hn) + self.m(hn.last, "Franklin", hn) + self.m(hn.nickname, "Ben", hn) + + def test_two_word_nickname_in_parenthesis(self) -> None: + hn = HumanName("Benjamin (Big Ben) Franklin") + self.m(hn.first, "Benjamin", hn) + self.m(hn.middle, "", hn) + self.m(hn.last, "Franklin", hn) + self.m(hn.nickname, "Big Ben", hn) + + def test_two_words_in_quotes(self) -> None: + hn = HumanName('Benjamin "Big Ben" Franklin') + self.m(hn.first, "Benjamin", hn) + self.m(hn.middle, "", hn) + self.m(hn.last, "Franklin", hn) + self.m(hn.nickname, "Big Ben", hn) + + def test_nickname_in_parenthesis_with_comma(self) -> None: + hn = HumanName("Franklin, Benjamin (Ben)") + self.m(hn.first, "Benjamin", hn) + self.m(hn.middle, "", hn) + self.m(hn.last, "Franklin", hn) + self.m(hn.nickname, "Ben", hn) + + def test_nickname_in_parenthesis_with_comma_and_suffix(self) -> None: + hn = HumanName("Franklin, Benjamin (Ben), Jr.") + self.m(hn.first, "Benjamin", hn) + self.m(hn.middle, "", hn) + self.m(hn.last, "Franklin", hn) + self.m(hn.suffix, "Jr.", hn) + self.m(hn.nickname, "Ben", hn) + + def test_nickname_in_single_quotes(self) -> None: + hn = HumanName("Benjamin 'Ben' Franklin") + self.m(hn.first, "Benjamin", hn) + self.m(hn.middle, "", hn) + self.m(hn.last, "Franklin", hn) + self.m(hn.nickname, "Ben", hn) + + def test_nickname_in_double_quotes(self) -> None: + hn = HumanName("Benjamin \"Ben\" Franklin") + self.m(hn.first, "Benjamin", hn) + self.m(hn.middle, "", hn) + self.m(hn.last, "Franklin", hn) + self.m(hn.nickname, "Ben", hn) + + def test_single_quotes_on_first_name_not_treated_as_nickname(self) -> None: + hn = HumanName("Brian Andrew O'connor") + self.m(hn.first, "Brian", hn) + self.m(hn.middle, "Andrew", hn) + self.m(hn.last, "O'connor", hn) + self.m(hn.nickname, "", hn) + + def test_single_quotes_on_both_name_not_treated_as_nickname(self) -> None: + hn = HumanName("La'tanya O'connor") + self.m(hn.first, "La'tanya", hn) + self.m(hn.middle, "", hn) + self.m(hn.last, "O'connor", hn) + self.m(hn.nickname, "", hn) + + def test_single_quotes_on_end_of_last_name_not_treated_as_nickname(self) -> None: + hn = HumanName("Mari' Aube'") + self.m(hn.first, "Mari'", hn) + self.m(hn.middle, "", hn) + self.m(hn.last, "Aube'", hn) + self.m(hn.nickname, "", hn) + + def test_okina_inside_name_not_treated_as_nickname(self) -> None: + hn = HumanName("Harrieta Keōpūolani Nāhiʻenaʻena") + self.m(hn.first, "Harrieta", hn) + self.m(hn.middle, "Keōpūolani", hn) + self.m(hn.last, "Nāhiʻenaʻena", hn) + self.m(hn.nickname, "", hn) + + def test_single_quotes_not_treated_as_nickname_Hawaiian_example(self) -> None: + hn = HumanName("Harietta Keopuolani Nahi'ena'ena") + self.m(hn.first, "Harietta", hn) + self.m(hn.middle, "Keopuolani", hn) + self.m(hn.last, "Nahi'ena'ena", hn) + self.m(hn.nickname, "", hn) + + def test_single_quotes_not_treated_as_nickname_Kenyan_example(self) -> None: + hn = HumanName("Naomi Wambui Ng'ang'a") + self.m(hn.first, "Naomi", hn) + self.m(hn.middle, "Wambui", hn) + self.m(hn.last, "Ng'ang'a", hn) + self.m(hn.nickname, "", hn) + + def test_single_quotes_not_treated_as_nickname_Samoan_example(self) -> None: + hn = HumanName("Va'apu'u Vitale") + self.m(hn.first, "Va'apu'u", hn) + self.m(hn.middle, "", hn) + self.m(hn.last, "Vitale", hn) + self.m(hn.nickname, "", hn) + + # http://code.google.com/p/python-nameparser/issues/detail?id=17 + def test_parenthesis_are_removed_from_name(self) -> None: + hn = HumanName("John Jones (Unknown)") + self.m(hn.first, "John", hn) + self.m(hn.last, "Jones", hn) + # not testing the nicknames because we don't actually care + # about Google Docs here + + def test_duplicate_parenthesis_are_removed_from_name(self) -> None: + hn = HumanName("John Jones (Google Docs), Jr. (Unknown)") + self.m(hn.first, "John", hn) + self.m(hn.last, "Jones", hn) + self.m(hn.suffix, "Jr.", hn) + + def test_nickname_and_last_name(self) -> None: + hn = HumanName('"Rick" Edmonds') + self.m(hn.first, "", hn) + self.m(hn.last, "Edmonds", hn) + self.m(hn.nickname, "Rick", hn) + + @pytest.mark.xfail + def test_nickname_and_last_name_with_title(self) -> None: + hn = HumanName('Senator "Rick" Edmonds') + self.m(hn.title, "Senator", hn) + self.m(hn.first, "", hn) + self.m(hn.last, "Edmonds", hn) + self.m(hn.nickname, "Rick", hn) + + +# class MaidenNameTestCase(HumanNameTestBase): +# +# def test_parenthesis_and_quotes_together(self): +# hn = HumanName("Jennifer 'Jen' Jones (Duff)") +# self.m(hn.first, "Jennifer", hn) +# self.m(hn.last, "Jones", hn) +# self.m(hn.nickname, "Jen", hn) +# self.m(hn.maiden, "Duff", hn) +# +# def test_maiden_name_with_nee(self): +# # https://en.wiktionary.org/wiki/née +# hn = HumanName("Mary Toogood nee Johnson") +# self.m(hn.first, "Mary", hn) +# self.m(hn.last, "Toogood", hn) +# self.m(hn.maiden, "Johnson", hn) +# +# def test_maiden_name_with_accented_nee(self): +# # https://en.wiktionary.org/wiki/née +# hn = HumanName("Mary Toogood née Johnson") +# self.m(hn.first, "Mary", hn) +# self.m(hn.last, "Toogood", hn) +# self.m(hn.maiden, "Johnson", hn) +# +# def test_maiden_name_with_nee_and_comma(self): +# # https://en.wiktionary.org/wiki/née +# hn = HumanName("Mary Toogood, née Johnson") +# self.m(hn.first, "Mary", hn) +# self.m(hn.last, "Toogood", hn) +# self.m(hn.maiden, "Johnson", hn) +# +# def test_maiden_name_with_nee_with_parenthesis(self): +# hn = HumanName("Mary Toogood (nee Johnson)") +# self.m(hn.first, "Mary", hn) +# self.m(hn.last, "Toogood", hn) +# self.m(hn.maiden, "Johnson", hn) +# +# def test_maiden_name_with_parenthesis(self): +# hn = HumanName("Mary Toogood (Johnson)") +# self.m(hn.first, "Mary", hn) diff --git a/tests/test_output_format.py b/tests/test_output_format.py new file mode 100644 index 0000000..a036752 --- /dev/null +++ b/tests/test_output_format.py @@ -0,0 +1,126 @@ +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +class HumanNameOutputFormatTests(HumanNameTestBase): + + def test_formatting_init_argument(self) -> None: + hn = HumanName("Rev John A. Kenneth Doe III (Kenny)", + string_format="TEST1") + self.assertEqual(str(hn), "TEST1") + + def test_formatting_constants_attribute(self) -> None: + from nameparser.config import CONSTANTS + _orig = CONSTANTS.string_format + CONSTANTS.string_format = "TEST2" + hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") + self.assertEqual(str(hn), "TEST2") + CONSTANTS.string_format = _orig + + def test_capitalize_name_constants_attribute(self) -> None: + from nameparser.config import CONSTANTS + CONSTANTS.capitalize_name = True + hn = HumanName("bob v. de la macdole-eisenhower phd") + self.assertEqual(str(hn), "Bob V. de la MacDole-Eisenhower Ph.D.") + CONSTANTS.capitalize_name = False + + def test_force_mixed_case_capitalization_constants_attribute(self) -> None: + from nameparser.config import CONSTANTS + CONSTANTS.force_mixed_case_capitalization = True + hn = HumanName('Shirley Maclaine') + hn.capitalize() + self.assertEqual(str(hn), "Shirley MacLaine") + CONSTANTS.force_mixed_case_capitalization = False + + def test_capitalize_name_and_force_mixed_case_capitalization_constants_attributes(self) -> None: + from nameparser.config import CONSTANTS + CONSTANTS.capitalize_name = True + CONSTANTS.force_mixed_case_capitalization = True + hn = HumanName('Shirley Maclaine') + self.assertEqual(str(hn), "Shirley MacLaine") + + def test_quote_nickname_formating(self) -> None: + hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") + hn.string_format = "{title} {first} {middle} {last} {suffix} '{nickname}'" + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III 'Kenny'") + hn.string_format = "{last}, {title} {first} {middle}, {suffix} '{nickname}'" + self.assertEqual(str(hn), "Doe, Rev John A. Kenneth, III 'Kenny'") + + def test_formating_removing_keys_from_format_string(self) -> None: + hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") + hn.string_format = "{title} {first} {middle} {last} {suffix} '{nickname}'" + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III 'Kenny'") + hn.string_format = "{last}, {title} {first} {middle}, {suffix}" + self.assertEqual(str(hn), "Doe, Rev John A. Kenneth, III") + hn.string_format = "{last}, {title} {first} {middle}" + self.assertEqual(str(hn), "Doe, Rev John A. Kenneth") + hn.string_format = "{last}, {first} {middle}" + self.assertEqual(str(hn), "Doe, John A. Kenneth") + hn.string_format = "{last}, {first}" + self.assertEqual(str(hn), "Doe, John") + hn.string_format = "{first} {last}" + self.assertEqual(str(hn), "John Doe") + + def test_formating_removing_pieces_from_name_buckets(self) -> None: + hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") + hn.string_format = "{title} {first} {middle} {last} {suffix} '{nickname}'" + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III 'Kenny'") + hn.string_format = "{title} {first} {middle} {last} {suffix}" + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III") + hn.middle = '' + self.assertEqual(str(hn), "Rev John Doe III") + hn.suffix = '' + self.assertEqual(str(hn), "Rev John Doe") + hn.title = '' + self.assertEqual(str(hn), "John Doe") + + def test_formating_of_nicknames_with_parenthesis(self) -> None: + hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") + hn.string_format = "{title} {first} {middle} {last} {suffix} ({nickname})" + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III (Kenny)") + hn.nickname = '' + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III") + + def test_formating_of_nicknames_with_single_quotes(self) -> None: + hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") + hn.string_format = "{title} {first} {middle} {last} {suffix} '{nickname}'" + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III 'Kenny'") + hn.nickname = '' + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III") + + def test_formating_of_nicknames_with_double_quotes(self) -> None: + hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") + hn.string_format = "{title} {first} {middle} {last} {suffix} \"{nickname}\"" + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III \"Kenny\"") + hn.nickname = '' + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III") + + def test_formating_of_nicknames_in_middle(self) -> None: + hn = HumanName("Rev John A. Kenneth Doe III (Kenny)") + hn.string_format = "{title} {first} ({nickname}) {middle} {last} {suffix}" + self.assertEqual(str(hn), "Rev John (Kenny) A. Kenneth Doe III") + hn.nickname = '' + self.assertEqual(str(hn), "Rev John A. Kenneth Doe III") + + def test_remove_emojis(self) -> None: + hn = HumanName("Sam Smith 😊") + self.m(hn.first, "Sam", hn) + self.m(hn.last, "Smith", hn) + self.assertEqual(str(hn), "Sam Smith") + + def test_keep_non_emojis(self) -> None: + hn = HumanName("∫≜⩕ Smith 😊") + self.m(hn.first, "∫≜⩕", hn) + self.m(hn.last, "Smith", hn) + self.assertEqual(str(hn), "∫≜⩕ Smith") + + def test_keep_emojis(self) -> None: + from nameparser.config import Constants + constants = Constants() + constants.regexes.emoji = False + hn = HumanName("∫≜⩕ Smith😊", constants) + self.m(hn.first, "∫≜⩕", hn) + self.m(hn.last, "Smith😊", hn) + self.assertEqual(str(hn), "∫≜⩕ Smith😊") + # test cleanup diff --git a/tests/test_prefixes.py b/tests/test_prefixes.py new file mode 100644 index 0000000..134f962 --- /dev/null +++ b/tests/test_prefixes.py @@ -0,0 +1,118 @@ +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +class PrefixesTestCase(HumanNameTestBase): + + def test_prefix(self) -> None: + hn = HumanName("Juan del Sur") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "del Sur", hn) + + def test_prefix_with_period(self) -> None: + hn = HumanName("Jill St. John") + self.m(hn.first, "Jill", hn) + self.m(hn.last, "St. John", hn) + + def test_prefix_before_two_part_last_name(self) -> None: + hn = HumanName("pennie von bergen wessels") + self.m(hn.first, "pennie", hn) + self.m(hn.last, "von bergen wessels", hn) + + def test_prefix_is_first_name(self) -> None: + hn = HumanName("Van Johnson") + self.m(hn.first, "Van", hn) + self.m(hn.last, "Johnson", hn) + + def test_prefix_is_first_name_with_middle_name(self) -> None: + hn = HumanName("Van Jeremy Johnson") + self.m(hn.first, "Van", hn) + self.m(hn.middle, "Jeremy", hn) + self.m(hn.last, "Johnson", hn) + + def test_prefix_before_two_part_last_name_with_suffix(self) -> None: + hn = HumanName("pennie von bergen wessels III") + self.m(hn.first, "pennie", hn) + self.m(hn.last, "von bergen wessels", hn) + self.m(hn.suffix, "III", hn) + + def test_prefix_before_two_part_last_name_with_acronym_suffix(self) -> None: + hn = HumanName("pennie von bergen wessels M.D.") + self.m(hn.first, "pennie", hn) + self.m(hn.last, "von bergen wessels", hn) + self.m(hn.suffix, "M.D.", hn) + + def test_two_part_last_name_with_suffix_comma(self) -> None: + hn = HumanName("pennie von bergen wessels, III") + self.m(hn.first, "pennie", hn) + self.m(hn.last, "von bergen wessels", hn) + self.m(hn.suffix, "III", hn) + + def test_two_part_last_name_with_suffix(self) -> None: + hn = HumanName("von bergen wessels, pennie III") + self.m(hn.first, "pennie", hn) + self.m(hn.last, "von bergen wessels", hn) + self.m(hn.suffix, "III", hn) + + def test_last_name_two_part_last_name_with_two_suffixes(self) -> None: + hn = HumanName("von bergen wessels MD, pennie III") + self.m(hn.first, "pennie", hn) + self.m(hn.last, "von bergen wessels", hn) + self.m(hn.suffix, "MD, III", hn) + + def test_comma_two_part_last_name_with_acronym_suffix(self) -> None: + hn = HumanName("von bergen wessels, pennie MD") + self.m(hn.first, "pennie", hn) + self.m(hn.last, "von bergen wessels", hn) + self.m(hn.suffix, "MD", hn) + + def test_comma_two_part_last_name_with_suffix_in_first_part(self) -> None: + # I'm kinda surprised this works, not really sure if this is a + # realistic place for a suffix to be. + hn = HumanName("von bergen wessels MD, pennie") + self.m(hn.first, "pennie", hn) + self.m(hn.last, "von bergen wessels", hn) + self.m(hn.suffix, "MD", hn) + + def test_title_two_part_last_name_with_suffix_in_first_part(self) -> None: + hn = HumanName("pennie von bergen wessels MD, III") + self.m(hn.first, "pennie", hn) + self.m(hn.last, "von bergen wessels", hn) + self.m(hn.suffix, "MD, III", hn) + + def test_portuguese_dos(self) -> None: + hn = HumanName("Rafael Sousa dos Anjos") + self.m(hn.first, "Rafael", hn) + self.m(hn.middle, "Sousa", hn) + self.m(hn.last, "dos Anjos", hn) + + def test_portuguese_prefixes(self) -> None: + hn = HumanName("Joao da Silva do Amaral de Souza") + self.m(hn.first, "Joao", hn) + self.m(hn.middle, "da Silva do Amaral", hn) + self.m(hn.last, "de Souza", hn) + + def test_three_conjunctions(self) -> None: + hn = HumanName("Dr. Juan Q. Xavier de la dos Vega III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la dos Vega", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "III", hn) + + def test_lastname_three_conjunctions(self) -> None: + hn = HumanName("de la dos Vega, Dr. Juan Q. Xavier III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la dos Vega", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "III", hn) + + def test_comma_three_conjunctions(self) -> None: + hn = HumanName("Dr. Juan Q. Xavier de la dos Vega, III") + self.m(hn.first, "Juan", hn) + self.m(hn.last, "de la dos Vega", hn) + self.m(hn.title, "Dr.", hn) + self.m(hn.middle, "Q. Xavier", hn) + self.m(hn.suffix, "III", hn) diff --git a/tests/test_python_api.py b/tests/test_python_api.py new file mode 100644 index 0000000..eed352d --- /dev/null +++ b/tests/test_python_api.py @@ -0,0 +1,226 @@ +import re + +import pytest + +try: + import dill +except ImportError: + dill = False # type: ignore[assignment] + +from nameparser import HumanName +from nameparser.config import Constants, TupleManager + +from tests.base import HumanNameTestBase + + +class HumanNamePythonTests(HumanNameTestBase): + + def test_utf8(self) -> None: + hn = HumanName("de la Véña, Jüan") + self.m(hn.first, "Jüan", hn) + self.m(hn.last, "de la Véña", hn) + + def test_string_output(self) -> None: + hn = HumanName("de la Véña, Jüan") + self.m(str(hn), "Jüan de la Véña", hn) + + def test_escaped_utf8_bytes(self) -> None: + hn = HumanName(b'B\xc3\xb6ck, Gerald') + self.m(hn.first, "Gerald", hn) + self.m(hn.last, "Böck", hn) + + def test_len(self) -> None: + hn = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") + self.m(len(hn), 5, hn) + hn = HumanName("John Doe") + self.m(len(hn), 2, hn) + + @pytest.mark.skipif(not dill, reason="requires python-dill module to test pickling") + def test_config_pickle(self) -> None: + constants = Constants() + self.assertTrue(dill.pickles(constants)) + + @pytest.mark.skipif(not dill, reason="requires python-dill module to test pickling") + def test_name_instance_pickle(self) -> None: + hn = HumanName("Title First Middle Middle Last, Jr.") + self.assertTrue(dill.pickles(hn)) + + def test_comparison(self) -> None: + hn1 = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") + hn2 = HumanName("Dr. John P. Doe-Ray, CLU, CFP, LUTC") + self.assertTrue(hn1 == hn2) + self.assertTrue(hn1 is not hn2) + self.assertTrue(hn1 == "Dr. John P. Doe-Ray CLU, CFP, LUTC") + hn1 = HumanName("Doe, Dr. John P., CLU, CFP, LUTC") + hn2 = HumanName("Dr. John P. Doe-Ray, CLU, CFP, LUTC") + self.assertTrue(not hn1 == hn2) + self.assertTrue(not hn1 == 0) + self.assertTrue(not hn1 == "test") + self.assertTrue(not hn1 == ["test"]) + self.assertTrue(not hn1 == {"test": hn2}) + + def test_assignment_to_full_name(self) -> None: + hn = HumanName("John A. Kenneth Doe, Jr.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.suffix, "Jr.", hn) + hn.full_name = "Juan Velasquez y Garcia III" + self.m(hn.first, "Juan", hn) + self.m(hn.last, "Velasquez y Garcia", hn) + self.m(hn.suffix, "III", hn) + + def test_get_full_name_attribute_references_internal_lists(self) -> None: + hn = HumanName("John Williams") + hn.first_list = ["Larry"] + self.m(hn.full_name, "Larry Williams", hn) + + def test_assignment_to_attribute(self) -> None: + hn = HumanName("John A. Kenneth Doe, Jr.") + hn.last = "de la Vega" + self.m(hn.last, "de la Vega", hn) + hn.title = "test" + self.m(hn.title, "test", hn) + hn.first = "test" + self.m(hn.first, "test", hn) + hn.middle = "test" + self.m(hn.middle, "test", hn) + hn.suffix = "test" + self.m(hn.suffix, "test", hn) + with pytest.raises(TypeError): + hn.suffix = [['test']] + with pytest.raises(TypeError): + hn.suffix = {"test": "test"} + + def test_assign_list_to_attribute(self) -> None: + hn = HumanName("John A. Kenneth Doe, Jr.") + hn.title = ["test1", "test2"] + self.m(hn.title, "test1 test2", hn) + hn.first = ["test3", "test4"] + self.m(hn.first, "test3 test4", hn) + hn.middle = ["test5", "test6", "test7"] + self.m(hn.middle, "test5 test6 test7", hn) + hn.last = ["test8", "test9", "test10"] + self.m(hn.last, "test8 test9 test10", hn) + hn.suffix = ['test'] + self.m(hn.suffix, "test", hn) + + def test_comparison_case_insensitive(self) -> None: + hn1 = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") + hn2 = HumanName("dr. john p. doe-Ray, CLU, CFP, LUTC") + self.assertTrue(hn1 == hn2) + self.assertTrue(hn1 is not hn2) + self.assertTrue(hn1 == "Dr. John P. Doe-ray clu, CFP, LUTC") + + def test_slice(self) -> None: + hn = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") + self.m(list(hn), ['Dr.', 'John', 'P.', 'Doe-Ray', 'CLU, CFP, LUTC'], hn) + self.m(hn[1:], ['John', 'P.', 'Doe-Ray', 'CLU, CFP, LUTC', hn.C.empty_attribute_default], hn) + self.m(hn[1:-2], ['John', 'P.', 'Doe-Ray'], hn) + + def test_getitem(self) -> None: + hn = HumanName("Dr. John A. Kenneth Doe, Jr.") + self.m(hn['title'], "Dr.", hn) + self.m(hn['first'], "John", hn) + self.m(hn['last'], "Doe", hn) + self.m(hn['middle'], "A. Kenneth", hn) + self.m(hn['suffix'], "Jr.", hn) + + def test_setitem(self) -> None: + hn = HumanName("Dr. John A. Kenneth Doe, Jr.") + hn['title'] = 'test' + self.m(hn['title'], "test", hn) + hn['last'] = ['test', 'test2'] + self.m(hn['last'], "test test2", hn) + with pytest.raises(TypeError): + hn["suffix"] = [['test']] + with pytest.raises(TypeError): + hn["suffix"] = {"test": "test"} + + def test_conjunction_names(self) -> None: + hn = HumanName("johnny y") + self.m(hn.first, "johnny", hn) + self.m(hn.last, "y", hn) + + def test_prefix_names(self) -> None: + hn = HumanName("vai la") + self.m(hn.first, "vai", hn) + self.m(hn.last, "la", hn) + + def test_blank_name(self) -> None: + hn = HumanName() + self.m(hn.first, "", hn) + self.m(hn.last, "", hn) + + def test_surnames_list_attribute(self) -> None: + hn = HumanName("John Edgar Casey Williams III") + self.m(hn.surnames_list, ["Edgar", "Casey", "Williams"], hn) + + def test_surnames_attribute(self) -> None: + hn = HumanName("John Edgar Casey Williams III") + self.m(hn.surnames, "Edgar Casey Williams", hn) + + def test_is_prefix_with_list(self) -> None: + hn = HumanName() + items = ['firstname', 'lastname', 'del'] + self.assertTrue(hn.is_prefix(items)) + self.assertTrue(hn.is_prefix(items[1:])) + + def test_is_conjunction_with_list(self) -> None: + hn = HumanName() + items = ['firstname', 'lastname', 'and'] + self.assertTrue(hn.is_conjunction(items)) + self.assertTrue(hn.is_conjunction(items[1:])) + + def test_override_constants(self) -> None: + C = Constants() + hn = HumanName(constants=C) + self.assertTrue(hn.C is C) + + def test_override_regex(self) -> None: + var = TupleManager([("spaces", re.compile(r"\s+", re.U)),]) + C = Constants(regexes=var) + hn = HumanName(constants=C) + self.assertTrue(hn.C.regexes == var) + + def test_override_titles(self) -> None: + var = ["abc","def"] + C = Constants(titles=var) + hn = HumanName(constants=C) + self.assertTrue(sorted(hn.C.titles) == sorted(var)) + + def test_override_first_name_titles(self) -> None: + var = ["abc","def"] + C = Constants(first_name_titles=var) + hn = HumanName(constants=C) + self.assertTrue(sorted(hn.C.first_name_titles) == sorted(var)) + + def test_override_prefixes(self) -> None: + var = ["abc","def"] + C = Constants(prefixes=var) + hn = HumanName(constants=C) + self.assertTrue(sorted(hn.C.prefixes) == sorted(var)) + + def test_override_suffix_acronyms(self) -> None: + var = ["abc","def"] + C = Constants(suffix_acronyms=var) + hn = HumanName(constants=C) + self.assertTrue(sorted(hn.C.suffix_acronyms) == sorted(var)) + + def test_override_suffix_not_acronyms(self) -> None: + var = ["abc","def"] + C = Constants(suffix_not_acronyms=var) + hn = HumanName(constants=C) + self.assertTrue(sorted(hn.C.suffix_not_acronyms) == sorted(var)) + + def test_override_conjunctions(self) -> None: + var = ["abc","def"] + C = Constants(conjunctions=var) + hn = HumanName(constants=C) + self.assertTrue(sorted(hn.C.conjunctions) == sorted(var)) + + def test_override_capitalization_exceptions(self) -> None: + var = TupleManager([("spaces", re.compile(r"\s+", re.U)),]) + C = Constants(capitalization_exceptions=var) + hn = HumanName(constants=C) + self.assertTrue(hn.C.capitalization_exceptions == var) diff --git a/tests/test_suffixes.py b/tests/test_suffixes.py new file mode 100644 index 0000000..b22945b --- /dev/null +++ b/tests/test_suffixes.py @@ -0,0 +1,138 @@ +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +class SuffixesTestCase(HumanNameTestBase): + + def test_suffix(self) -> None: + hn = HumanName("Joe Franklin Jr") + self.m(hn.first, "Joe", hn) + self.m(hn.last, "Franklin", hn) + self.m(hn.suffix, "Jr", hn) + + def test_suffix_with_periods(self) -> None: + hn = HumanName("Joe Dentist D.D.S.") + self.m(hn.first, "Joe", hn) + self.m(hn.last, "Dentist", hn) + self.m(hn.suffix, "D.D.S.", hn) + + def test_two_suffixes(self) -> None: + hn = HumanName("Kenneth Clarke QC MP") + self.m(hn.first, "Kenneth", hn) + self.m(hn.last, "Clarke", hn) + # NOTE: this adds a comma when the original format did not have one. + # not ideal but at least its in the right bucket + self.m(hn.suffix, "QC, MP", hn) + + def test_two_suffixes_lastname_comma_format(self) -> None: + hn = HumanName("Washington Jr. MD, Franklin") + self.m(hn.first, "Franklin", hn) + self.m(hn.last, "Washington", hn) + # NOTE: this adds a comma when the original format did not have one. + self.m(hn.suffix, "Jr., MD", hn) + + def test_two_suffixes_suffix_comma_format(self) -> None: + hn = HumanName("Franklin Washington, Jr. MD") + self.m(hn.first, "Franklin", hn) + self.m(hn.last, "Washington", hn) + self.m(hn.suffix, "Jr. MD", hn) + + def test_suffix_containing_periods(self) -> None: + hn = HumanName("Kenneth Clarke Q.C.") + self.m(hn.first, "Kenneth", hn) + self.m(hn.last, "Clarke", hn) + self.m(hn.suffix, "Q.C.", hn) + + def test_suffix_containing_periods_lastname_comma_format(self) -> None: + hn = HumanName("Clarke, Kenneth, Q.C. M.P.") + self.m(hn.first, "Kenneth", hn) + self.m(hn.last, "Clarke", hn) + self.m(hn.suffix, "Q.C. M.P.", hn) + + def test_suffix_containing_periods_suffix_comma_format(self) -> None: + hn = HumanName("Kenneth Clarke Q.C., M.P.") + self.m(hn.first, "Kenneth", hn) + self.m(hn.last, "Clarke", hn) + self.m(hn.suffix, "Q.C., M.P.", hn) + + def test_suffix_with_single_comma_format(self) -> None: + hn = HumanName("John Doe jr., MD") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "jr., MD", hn) + + def test_suffix_with_double_comma_format(self) -> None: + hn = HumanName("Doe, John jr., MD") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "jr., MD", hn) + + def test_phd_with_erroneous_space(self) -> None: + hn = HumanName("John Smith, Ph. D.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Smith", hn) + self.m(hn.suffix, "Ph. D.", hn) + + def test_phd_extracted_without_comma(self) -> None: + hn = HumanName("John Smith Ph. D.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Smith", hn) + self.m(hn.suffix, "Ph. D.", hn) + + def test_phd_conflict(self) -> None: + hn = HumanName("Adolph D") + self.m(hn.first, "Adolph", hn) + self.m(hn.last, "D", hn) + + # http://en.wikipedia.org/wiki/Ma_(surname) + + def test_potential_suffix_that_is_also_last_name(self) -> None: + hn = HumanName("Jack Ma") + self.m(hn.first, "Jack", hn) + self.m(hn.last, "Ma", hn) + + def test_potential_suffix_that_is_also_last_name_comma(self) -> None: + hn = HumanName("Ma, Jack") + self.m(hn.first, "Jack", hn) + self.m(hn.last, "Ma", hn) + + def test_potential_suffix_that_is_also_last_name_with_suffix(self) -> None: + hn = HumanName("Jack Ma Jr") + self.m(hn.first, "Jack", hn) + self.m(hn.last, "Ma", hn) + self.m(hn.suffix, "Jr", hn) + + def test_potential_suffix_that_is_also_last_name_with_suffix_comma(self) -> None: + hn = HumanName("Ma III, Jack Jr") + self.m(hn.first, "Jack", hn) + self.m(hn.last, "Ma", hn) + self.m(hn.suffix, "III, Jr", hn) + + # https://github.com/derek73/python-nameparser/issues/27 + @pytest.mark.xfail + def test_king(self) -> None: + hn = HumanName("Dr King Jr") + self.m(hn.title, "Dr", hn) + self.m(hn.last, "King", hn) + self.m(hn.suffix, "Jr", hn) + + def test_multiple_letter_suffix_with_periods(self) -> None: + hn = HumanName("John Doe Msc.Ed.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "Msc.Ed.", hn) + + def test_suffix_with_periods_with_comma(self) -> None: + hn = HumanName("John Doe, Msc.Ed.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "Msc.Ed.", hn) + + def test_suffix_with_periods_with_lastname_comma(self) -> None: + hn = HumanName("Doe, John Msc.Ed.") + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.suffix, "Msc.Ed.", hn) diff --git a/tests/test_titles.py b/tests/test_titles.py new file mode 100644 index 0000000..7b06121 --- /dev/null +++ b/tests/test_titles.py @@ -0,0 +1,241 @@ +import pytest + +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +class TitleTestCase(HumanNameTestBase): + + def test_last_name_is_also_title(self) -> None: + hn = HumanName("Amy E Maid") + self.m(hn.first, "Amy", hn) + self.m(hn.middle, "E", hn) + self.m(hn.last, "Maid", hn) + + def test_last_name_is_also_title_no_comma(self) -> None: + hn = HumanName("Dr. Martin Luther King Jr.") + self.m(hn.title, "Dr.", hn) + self.m(hn.first, "Martin", hn) + self.m(hn.middle, "Luther", hn) + self.m(hn.last, "King", hn) + self.m(hn.suffix, "Jr.", hn) + + def test_last_name_is_also_title_with_comma(self) -> None: + hn = HumanName("Dr Martin Luther King, Jr.") + self.m(hn.title, "Dr", hn) + self.m(hn.first, "Martin", hn) + self.m(hn.middle, "Luther", hn) + self.m(hn.last, "King", hn) + self.m(hn.suffix, "Jr.", hn) + + def test_last_name_is_also_title3(self) -> None: + hn = HumanName("John King") + self.m(hn.first, "John", hn) + self.m(hn.last, "King", hn) + + def test_title_with_conjunction(self) -> None: + hn = HumanName("Secretary of State Hillary Clinton") + self.m(hn.title, "Secretary of State", hn) + self.m(hn.first, "Hillary", hn) + self.m(hn.last, "Clinton", hn) + + def test_compound_title_with_conjunction(self) -> None: + hn = HumanName("Cardinal Secretary of State Hillary Clinton") + self.m(hn.title, "Cardinal Secretary of State", hn) + self.m(hn.first, "Hillary", hn) + self.m(hn.last, "Clinton", hn) + + def test_title_is_title(self) -> None: + hn = HumanName("Coach") + self.m(hn.title, "Coach", hn) + + # TODO: fix handling of U.S. + @pytest.mark.xfail + def test_chained_title_first_name_title_is_initials(self) -> None: + hn = HumanName("U.S. District Judge Marc Thomas Treadwell") + self.m(hn.title, "U.S. District Judge", hn) + self.m(hn.first, "Marc", hn) + self.m(hn.middle, "Thomas", hn) + self.m(hn.last, "Treadwell", hn) + + def test_conflict_with_chained_title_first_name_initial(self) -> None: + hn = HumanName("U. S. Grant") + self.m(hn.first, "U.", hn) + self.m(hn.middle, "S.", hn) + self.m(hn.last, "Grant", hn) + + def test_chained_title_first_name_initial_with_no_period(self) -> None: + hn = HumanName("US Magistrate Judge T Michael Putnam") + self.m(hn.title, "US Magistrate Judge", hn) + self.m(hn.first, "T", hn) + self.m(hn.middle, "Michael", hn) + self.m(hn.last, "Putnam", hn) + + def test_chained_hyphenated_title(self) -> None: + hn = HumanName("US Magistrate-Judge Elizabeth E Campbell") + self.m(hn.title, "US Magistrate-Judge", hn) + self.m(hn.first, "Elizabeth", hn) + self.m(hn.middle, "E", hn) + self.m(hn.last, "Campbell", hn) + + def test_chained_hyphenated_title_with_comma_suffix(self) -> None: + hn = HumanName("Mag-Judge Harwell G Davis, III") + self.m(hn.title, "Mag-Judge", hn) + self.m(hn.first, "Harwell", hn) + self.m(hn.middle, "G", hn) + self.m(hn.last, "Davis", hn) + self.m(hn.suffix, "III", hn) + + @pytest.mark.xfail + def test_title_multiple_titles_with_apostrophe_s(self) -> None: + hn = HumanName("The Right Hon. the President of the Queen's Bench Division") + self.m(hn.title, "The Right Hon. the President of the Queen's Bench Division", hn) + + def test_title_starts_with_conjunction(self) -> None: + hn = HumanName("The Rt Hon John Jones") + self.m(hn.title, "The Rt Hon", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Jones", hn) + + def test_conjunction_before_title(self) -> None: + hn = HumanName('The Lord of the Universe') + self.m(hn.title, "The Lord of the Universe", hn) + + def test_double_conjunction_on_title(self) -> None: + hn = HumanName('Lord of the Universe') + self.m(hn.title, "Lord of the Universe", hn) + + def test_triple_conjunction_on_title(self) -> None: + hn = HumanName('Lord and of the Universe') + self.m(hn.title, "Lord and of the Universe", hn) + + def test_multiple_conjunctions_on_multiple_titles(self) -> None: + hn = HumanName('Lord of the Universe and Associate Supreme Queen of the World Lisa Simpson') + self.m(hn.title, "Lord of the Universe and Associate Supreme Queen of the World", hn) + self.m(hn.first, "Lisa", hn) + self.m(hn.last, "Simpson", hn) + + def test_title_with_last_initial_is_suffix(self) -> None: + hn = HumanName("King John V.") + self.m(hn.title, "King", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "V.", hn) + + def test_initials_also_suffix(self) -> None: + hn = HumanName("Smith, J.R.") + self.m(hn.first, "J.R.", hn) + # self.m(hn.middle, "R.", hn) + self.m(hn.last, "Smith", hn) + + def test_two_title_parts_separated_by_periods(self) -> None: + hn = HumanName("Lt.Gen. John A. Kenneth Doe IV") + self.m(hn.title, "Lt.Gen.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.suffix, "IV", hn) + + def test_two_part_title(self) -> None: + hn = HumanName("Lt. Gen. John A. Kenneth Doe IV") + self.m(hn.title, "Lt. Gen.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.suffix, "IV", hn) + + def test_two_part_title_with_lastname_comma(self) -> None: + hn = HumanName("Doe, Lt. Gen. John A. Kenneth IV") + self.m(hn.title, "Lt. Gen.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.suffix, "IV", hn) + + def test_two_part_title_with_suffix_comma(self) -> None: + hn = HumanName("Lt. Gen. John A. Kenneth Doe, Jr.") + self.m(hn.title, "Lt. Gen.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A. Kenneth", hn) + self.m(hn.suffix, "Jr.", hn) + + def test_possible_conflict_with_middle_initial_that_could_be_suffix(self) -> None: + hn = HumanName("Doe, Rev. John V, Jr.") + self.m(hn.title, "Rev.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "V", hn) + self.m(hn.suffix, "Jr.", hn) + + def test_possible_conflict_with_suffix_that_could_be_initial(self) -> None: + hn = HumanName("Doe, Rev. John A., V, Jr.") + self.m(hn.title, "Rev.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + self.m(hn.middle, "A.", hn) + self.m(hn.suffix, "V, Jr.", hn) + + # 'ben' is removed from PREFIXES in v0.2.5 + # this test could re-enable this test if we decide to support 'ben' as a prefix + @pytest.mark.xfail + def test_ben_as_conjunction(self) -> None: + hn = HumanName("Ahmad ben Husain") + self.m(hn.first, "Ahmad", hn) + self.m(hn.last, "ben Husain", hn) + + def test_ben_as_first_name(self) -> None: + hn = HumanName("Ben Johnson") + self.m(hn.first, "Ben", hn) + self.m(hn.last, "Johnson", hn) + + def test_ben_as_first_name_with_middle_name(self) -> None: + hn = HumanName("Ben Alex Johnson") + self.m(hn.first, "Ben", hn) + self.m(hn.middle, "Alex", hn) + self.m(hn.last, "Johnson", hn) + + def test_ben_as_middle_name(self) -> None: + hn = HumanName("Alex Ben Johnson") + self.m(hn.first, "Alex", hn) + self.m(hn.middle, "Ben", hn) + self.m(hn.last, "Johnson", hn) + + # http://code.google.com/p/python-nameparser/issues/detail?id=13 + def test_last_name_also_prefix(self) -> None: + hn = HumanName("Jane Doctor") + self.m(hn.first, "Jane", hn) + self.m(hn.last, "Doctor", hn) + + def test_title_with_periods(self) -> None: + hn = HumanName("Lt.Gov. John Doe") + self.m(hn.title, "Lt.Gov.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + + def test_title_with_periods_lastname_comma(self) -> None: + hn = HumanName("Doe, Lt.Gov. John") + self.m(hn.title, "Lt.Gov.", hn) + self.m(hn.first, "John", hn) + self.m(hn.last, "Doe", hn) + + def test_mac_with_spaces(self) -> None: + hn = HumanName("Jane Mac Beth") + self.m(hn.first, "Jane", hn) + self.m(hn.last, "Mac Beth", hn) + + def test_mac_as_first_name(self) -> None: + hn = HumanName("Mac Miller") + self.m(hn.first, "Mac", hn) + self.m(hn.last, "Miller", hn) + + def test_multiple_prefixes(self) -> None: + hn = HumanName("Mike van der Velt") + self.m(hn.first, "Mike", hn) + self.m(hn.last, "van der Velt", hn) + + def test_2_same_prefixes_in_the_name(self) -> None: + hh = HumanName("Vincent van Gogh van Beethoven") + self.m(hh.first, "Vincent", hh) + self.m(hh.middle, "van Gogh", hh) + self.m(hh.last, "van Beethoven", hh) diff --git a/tests/test_variations.py b/tests/test_variations.py new file mode 100644 index 0000000..6edccee --- /dev/null +++ b/tests/test_variations.py @@ -0,0 +1,211 @@ +from nameparser import HumanName + +from tests.base import HumanNameTestBase + + +TEST_NAMES = ( + "John Doe", + "John Doe, Jr.", + "John Doe III", + "Doe, John", + "Doe, John, Jr.", + "Doe, John III", + "John A. Doe", + "John A. Doe, Jr.", + "John A. Doe III", + "Doe, John A.", + "Doe, John A., Jr.", + "Doe, John A. III", + "John A. Kenneth Doe", + "John A. Kenneth Doe, Jr.", + "John A. Kenneth Doe III", + "Doe, John A. Kenneth", + "Doe, John A. Kenneth, Jr.", + "Doe, John A. Kenneth III", + "Dr. John Doe", + "Dr. John Doe, Jr.", + "Dr. John Doe III", + "Doe, Dr. John", + "Doe, Dr. John, Jr.", + "Doe, Dr. John III", + "Dr. John A. Doe", + "Dr. John A. Doe, Jr.", + "Dr. John A. Doe III", + "Doe, Dr. John A.", + "Doe, Dr. John A. Jr.", + "Doe, Dr. John A. III", + "Dr. John A. Kenneth Doe", + "Dr. John A. Kenneth Doe, Jr.", + "Dr. John A. Kenneth Doe III", + "Doe, Dr. John A. Kenneth", + "Doe, Dr. John A. Kenneth Jr.", + "Doe, Dr. John A. Kenneth III", + "Juan de la Vega", + "Juan de la Vega, Jr.", + "Juan de la Vega III", + "de la Vega, Juan", + "de la Vega, Juan, Jr.", + "de la Vega, Juan III", + "Juan Velasquez y Garcia", + "Juan Velasquez y Garcia, Jr.", + "Juan Velasquez y Garcia III", + "Velasquez y Garcia, Juan", + "Velasquez y Garcia, Juan, Jr.", + "Velasquez y Garcia, Juan III", + "Dr. Juan de la Vega", + "Dr. Juan de la Vega, Jr.", + "Dr. Juan de la Vega III", + "de la Vega, Dr. Juan", + "de la Vega, Dr. Juan, Jr.", + "de la Vega, Dr. Juan III", + "Dr. Juan Velasquez y Garcia", + "Dr. Juan Velasquez y Garcia, Jr.", + "Dr. Juan Velasquez y Garcia III", + "Velasquez y Garcia, Dr. Juan", + "Velasquez y Garcia, Dr. Juan, Jr.", + "Velasquez y Garcia, Dr. Juan III", + "Juan Q. de la Vega", + "Juan Q. de la Vega, Jr.", + "Juan Q. de la Vega III", + "de la Vega, Juan Q.", + "de la Vega, Juan Q., Jr.", + "de la Vega, Juan Q. III", + "Juan Q. Velasquez y Garcia", + "Juan Q. Velasquez y Garcia, Jr.", + "Juan Q. Velasquez y Garcia III", + "Velasquez y Garcia, Juan Q.", + "Velasquez y Garcia, Juan Q., Jr.", + "Velasquez y Garcia, Juan Q. III", + "Dr. Juan Q. de la Vega", + "Dr. Juan Q. de la Vega, Jr.", + "Dr. Juan Q. de la Vega III", + "de la Vega, Dr. Juan Q.", + "de la Vega, Dr. Juan Q., Jr.", + "de la Vega, Dr. Juan Q. III", + "Dr. Juan Q. Velasquez y Garcia", + "Dr. Juan Q. Velasquez y Garcia, Jr.", + "Dr. Juan Q. Velasquez y Garcia III", + "Velasquez y Garcia, Dr. Juan Q.", + "Velasquez y Garcia, Dr. Juan Q., Jr.", + "Velasquez y Garcia, Dr. Juan Q. III", + "Juan Q. Xavier de la Vega", + "Juan Q. Xavier de la Vega, Jr.", + "Juan Q. Xavier de la Vega III", + "de la Vega, Juan Q. Xavier", + "de la Vega, Juan Q. Xavier, Jr.", + "de la Vega, Juan Q. Xavier III", + "Juan Q. Xavier Velasquez y Garcia", + "Juan Q. Xavier Velasquez y Garcia, Jr.", + "Juan Q. Xavier Velasquez y Garcia III", + "Velasquez y Garcia, Juan Q. Xavier", + "Velasquez y Garcia, Juan Q. Xavier, Jr.", + "Velasquez y Garcia, Juan Q. Xavier III", + "Dr. Juan Q. Xavier de la Vega", + "Dr. Juan Q. Xavier de la Vega, Jr.", + "Dr. Juan Q. Xavier de la Vega III", + "de la Vega, Dr. Juan Q. Xavier", + "de la Vega, Dr. Juan Q. Xavier, Jr.", + "de la Vega, Dr. Juan Q. Xavier III", + "Dr. Juan Q. Xavier Velasquez y Garcia", + "Dr. Juan Q. Xavier Velasquez y Garcia, Jr.", + "Dr. Juan Q. Xavier Velasquez y Garcia III", + "Velasquez y Garcia, Dr. Juan Q. Xavier", + "Velasquez y Garcia, Dr. Juan Q. Xavier, Jr.", + "Velasquez y Garcia, Dr. Juan Q. Xavier III", + "John Doe, CLU, CFP, LUTC", + "John P. Doe, CLU, CFP, LUTC", + "Dr. John P. Doe-Ray, CLU, CFP, LUTC", + "Doe-Ray, Dr. John P., CLU, CFP, LUTC", + "Hon. Barrington P. Doe-Ray, Jr.", + "Doe-Ray, Hon. Barrington P. Jr.", + "Doe-Ray, Hon. Barrington P. Jr., CFP, LUTC", + "Jose Aznar y Lopez", + "John E Smith", + "John e Smith", + "John and Jane Smith", + "Rev. John A. Kenneth Doe", + "Donovan McNabb-Smith", + "Rev John A. Kenneth Doe", + "Doe, Rev. John A. Jr.", + "Buca di Beppo", + "Lt. Gen. John A. Kenneth Doe, Jr.", + "Doe, Lt. Gen. John A. Kenneth IV", + "Lt. Gen. John A. Kenneth Doe IV", + 'Mr. and Mrs. John Smith', + 'John Jones (Google Docs)', + 'john e jones', + 'john e jones, III', + 'jones, john e', + 'E.T. Smith', + 'E.T. Smith, II', + 'Smith, E.T., Jr.', + 'A.B. Vajpayee', + 'Rt. Hon. Paul E. Mary', + 'Maid Marion', + 'Amy E. Maid', + 'Jane Doctor', + 'Doctor, Jane E.', + 'dr. ben alex johnson III', + 'Lord of the Universe and Supreme King of the World Lisa Simpson', + 'Benjamin (Ben) Franklin', + 'Benjamin "Ben" Franklin', + "Brian O'connor", + "Sir Gerald", + "Magistrate Judge John F. Forster, Jr", + # "Magistrate Judge Joaquin V.E. Manibusan, Jr", Intials seem to mess this up + "Magistrate-Judge Elizabeth Todd Campbell", + "Mag-Judge Harwell G Davis, III", + "Mag. Judge Byron G. Cudmore", + "Chief Judge J. Leon Holmes", + "Chief Judge Sharon Lovelace Blackburn", + "Judge James M. Moody", + "Judge G. Thomas Eisele", + # "Judge Callie V. S. Granade", + "Judge C Lynwood Smith, Jr", + "Senior Judge Charles R. Butler, Jr", + "Senior Judge Harold D. Vietor", + "Senior Judge Virgil Pittman", + "Honorable Terry F. Moorer", + "Honorable W. Harold Albritton, III", + "Honorable Judge W. Harold Albritton, III", + "Honorable Judge Terry F. Moorer", + "Honorable Judge Susan Russ Walker", + "Hon. Marian W. Payson", + "Hon. Charles J. Siragusa", + "US Magistrate Judge T Michael Putnam", + "Designated Judge David A. Ezra", + "Sr US District Judge Richard G Kopf", + "U.S. District Judge Marc Thomas Treadwell", + "Dra. Andréia da Silva", + "Srta. Andréia da Silva", + +) + + +class HumanNameVariationTests(HumanNameTestBase): + # test automated variations of names in TEST_NAMES. + # Helps test that the 3 code trees work the same + + TEST_NAMES = TEST_NAMES + + def test_variations_of_TEST_NAMES(self) -> None: + for name in self.TEST_NAMES: + hn = HumanName(name) + if len(hn.suffix_list) > 1: + hn = HumanName("{title} {first} {middle} {last} {suffix}".format(**hn.as_dict()).split(',')[0]) + hn.C.empty_attribute_default = '' # format strings below require empty string + hn_dict = hn.as_dict() + nocomma = HumanName("{title} {first} {middle} {last} {suffix}".format(**hn_dict)) + lastnamecomma = HumanName("{last}, {title} {first} {middle} {suffix}".format(**hn_dict)) + if hn.suffix: + suffixcomma = HumanName("{title} {first} {middle} {last}, {suffix}".format(**hn_dict)) + if hn.nickname: + nocomma = HumanName("{title} {first} {middle} {last} {suffix} ({nickname})".format(**hn_dict)) + lastnamecomma = HumanName("{last}, {title} {first} {middle} {suffix} ({nickname})".format(**hn_dict)) + if hn.suffix: + suffixcomma = HumanName("{title} {first} {middle} {last}, {suffix} ({nickname})".format(**hn_dict)) + for attr in hn._members: + self.m(getattr(hn, attr), getattr(nocomma, attr), hn) + self.m(getattr(hn, attr), getattr(lastnamecomma, attr), hn) + if hn.suffix: + self.m(getattr(hn, attr), getattr(suffixcomma, attr), hn) diff --git a/uv.lock b/uv.lock index a4818aa..c01beca 100644 --- a/uv.lock +++ b/uv.lock @@ -224,6 +224,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" }, ] +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + [[package]] name = "idna" version = "3.18" @@ -242,6 +254,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5f/53/fb7122b71361a0d121b669dcf3d31244ef75badbbb724af388948de543e2/imagesize-2.0.0-py2.py3-none-any.whl", hash = "sha256:5667c5bbb57ab3f1fa4bc366f4fbc971db3d5ed011fd2715fd8001f782718d96", size = 9441, upload-time = "2026-03-03T14:18:27.892Z" }, ] +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + [[package]] name = "jinja2" version = "3.1.6" @@ -503,6 +524,7 @@ dependencies = [ dev = [ { name = "dill" }, { name = "mypy" }, + { name = "pytest" }, { name = "ruff" }, { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, @@ -516,6 +538,7 @@ requires-dist = [{ name = "typing-extensions", marker = "python_full_version < ' dev = [ { name = "dill", specifier = ">=0.2.5" }, { name = "mypy", specifier = ">=2.1" }, + { name = "pytest", specifier = ">=8" }, { name = "ruff", specifier = ">=0.15" }, { name = "sphinx", specifier = ">=8" }, ] @@ -538,6 +561,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, ] +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + [[package]] name = "pygments" version = "2.20.0" @@ -547,6 +579,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] +[[package]] +name = "pytest" +version = "9.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/0e/b5858858d74958632c49b72cb25a3976ff9f632397626715be71c89d3971/pytest-9.1.0.tar.gz", hash = "sha256:41dd9148c08072446394cefd3d79701701335a9f4cae69ba92e39f6c7f5c061c", size = 1634181, upload-time = "2026-06-13T18:52:45.983Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/5a/ba30a81239b909821b3153e303e7def45178bf353da4f72380e6c5e8793b/pytest-9.1.0-py3-none-any.whl", hash = "sha256:8ebb0e7888bdf2bdfc602ec51f8f62d50200af37356c74e503c79a94f5c81f32", size = 386453, upload-time = "2026-06-13T18:52:44.045Z" }, +] + [[package]] name = "requests" version = "2.34.2"