Metadata-Version: 2.4
Name: nominate
Version: 0.1.0
Summary: Generate random human names under constraints, weighted by real-world frequency data.
Project-URL: Homepage, https://github.com/paine/nominate
Author: nominate contributors
License: MIT
Keywords: characters,generator,names,onomastics,random
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Requires-Dist: nameparser>=1.1
Requires-Dist: numpy>=1.24
Requires-Dist: pronouncing>=0.2
Requires-Dist: pyarrow>=14
Requires-Dist: typer>=0.12
Requires-Dist: unidecode>=1.3
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Provides-Extra: pipeline
Requires-Dist: huggingface-hub>=1.22; extra == 'pipeline'
Requires-Dist: pandas>=2.0; extra == 'pipeline'
Description-Content-Type: text/markdown

# nominate

Generate random human names under constraints, weighted by real-world frequency data.

`nominate` samples forenames and surnames from country-level census/demographic
frequency data (derived from the [Onomaverse names dataset](https://onomaverse.com/datasets),
CC BY 4.0), so generated names are as common or as rare as you ask them to be.
It is built for narrative use ("name this character") but works anywhere you
need plausible names.

The full dataset (110 countries, ~6 MB) ships inside the package — no
downloads, no network access at runtime.

## Features

- Weighted sampling: names are drawn proportionally to how often they actually occur.
- Convention-aware rendering: countries that write the family name first
  (Vietnam, Korea, China, Hungary, ...) come out that way ("Nguyễn Văn An").
- Constraints: country/region, gender, syllable count, regex, rhyme / phoneme
  inclusion-exclusion, uniqueness (exclusion lists), and commonness percentiles.
- Partial names: freeze known forenames/surnames and complete the rest.
- Reverse classification: given a name, estimate gender and likely countries.
- Python API and a CLI.

## Install

```bash
pip install nominate
```

## Quick start (Python)

```python
from nominate import NameGenerator

gen = NameGenerator(countries=["US"], seed=42)

# One forename + one surname, letting the data decide gender:
name = gen.generate()
print(name.full)

# A common-ish two-syllable feminine name starting with A:
name = gen.generate(
    gender="F",
    syllables=(2, 3),
    regex=r"^A",
    percentile=(0.5, 1.0),
)

# Complete a partial name ("I know the first name, need a surname"):
name = gen.generate(forenames=1, surnames=1, frozen_forenames=["James"])

# A sibling for an existing character (shared surname, unique forename):
name = gen.generate(
    frozen_surnames=["Kowalski"],
    exclude={"Anna"},          # already used
)

# Rhymes and phonemes:
name = gen.generate(rhymes_with="Kelly", exclude_phonemes=["TH"])

# Whole regions, or everything:
gen = NameGenerator(region="europe")
gen = NameGenerator()          # all 110 countries
```

Reverse classification:

```python
from nominate import classify

result = classify("Anna Kowalska")
result.gender_probabilities   # {"F": 0.997, "M": 0.003}
result.countries              # [("PL", 0.75), ("SE", 0.03), ...]

# Family-name-first names are detected and read in the right order:
result = classify("Nguyễn Văn An")
result.forename, result.surname   # ("An", "Nguyễn")
result.surname_first              # True
```

## Quick start (CLI)

```bash
# Generate names:
nominate generate -c US -n 10
nominate generate -c US --gender f --syllables 2-3 --regex '^A' \
    --percentile 25-90 -n 5
nominate generate -c US --freeze-forename James -n 3
nominate generate --region europe -n 5
nominate generate -c US --rhymes-with Kelly --exclude-file used_names.txt

# Classify a name:
nominate classify "Anna Kowalska"

# Inspect the bundled data:
nominate data status
nominate data list --region oceania
```

## Constraints reference

| Constraint | Python argument | CLI flag |
| --- | --- | --- |
| Country / region | `NameGenerator(countries=[...])`, `region="europe"` | `--country/-c` (repeatable), `--region` |
| Gender | `gender="M"/"F"`, `strict_gender=True` | `--gender`, `--strict-gender` |
| Syllables | `syllables=2` or `syllables=(2, 3)` | `--syllables 2` or `2-3` |
| Regex | `regex=r"^A.*y$"` (case-insensitive by default) | `--regex` |
| Rhyme | `rhymes_with="Kelly"` | `--rhymes-with` |
| Phonemes | `include_phonemes=[...]`, `exclude_phonemes=[...]` (ARPAbet) | `--include-phoneme`, `--exclude-phoneme` |
| Uniqueness | `exclude={...}` | `--exclude`, `--exclude-file` |
| Likelihood | `percentile=(0.25, 0.9)` (or 25-90) | `--percentile 25-90` |

Percentiles are within a country and name kind: `percentile=(0.9, 1.0)` means
"the most common 10% of names", `(0.0, 0.1)` means "the rarest 10%".

By default, gendered sampling trusts the data: a name that is recorded for both
genders can be drawn for either, proportionally to its counts. Passing
`strict_gender=True` additionally drops names whose *majority* gender does not
match the requested one.

## Data

Per-country Parquet files (`given/US.parquet`, `surname/US.parquet`, ...) are
bundled at `nominate/_bundled/` inside the package. They are produced by the
scripts in [`pipeline/`](pipeline/), which merge several sources — the
Onomaverse frequency data (via a
[Hugging Face bucket](https://huggingface.co/buckets/benjamin-paine/names-bucket)),
the erpel1 Kaggle forenames/surnames dataset, and sigpwned's
popular-names-by-country dataset — so that countries with thin census
coverage are backfilled rather than silently underrepresented. Supplementary
counts are rescaled or Zipf-extrapolated onto each country's measured scale
and never override measured data. Everything is enriched with romanizations,
ARPAbet phonemes, syllable counts, rhyme keys, and percentile ranks. See
`pipeline/README.md` for details and how to rebuild.

You can point the library at a custom build with
`NameGenerator(data_dir=...)` or the `NOMINATE_DATA_DIR` environment variable.

Phonetics are Latin-script oriented: names are romanized (via Onomaverse
transliterations, falling back to `unidecode`) and looked up in CMUdict, with
a heuristic grapheme-to-phoneme fallback for names CMUdict does not know.

## Attribution

Bundled data is derived from:

- [Onomaverse](https://onomaverse.com/datasets) names datasets, licensed
  [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
- [Forenames and Surnames with Gender and Country](https://www.kaggle.com/datasets/erpel1/forenames-and-surnames-with-gender-and-country)
  by erpel1 (Kaggle), licensed Apache 2.0.
- [vietnamese-namedb](https://github.com/duyet/vietnamese-namedb)
  by duyet, licensed MIT.
- [popular-names-by-country-dataset](https://github.com/sigpwned/popular-names-by-country-dataset)
  by sigpwned, licensed CC0 1.0.

## License

MIT (code). Bundled data: CC BY 4.0 (see Attribution).
