GBIF scientific name parser — Rust core, Python binding
Project description
nameparser-py — native Python binding
import nameparser gives you the Rust nameparser core's parse() directly, as a
PyO3 extension module. Unlike bindings/java (which crosses the JVM/native
boundary via java.lang.foreign, either JSON or a flat struct on the wire), there is no
C-ABI or marshalling floor here: PyO3 wraps the core nameparser::model::ParsedName struct
directly, with one getter per field mapping it straight to its idiomatic Python type — no JVM,
no JSON round-trip, no separately-installed native library to locate at runtime.
Field parity with the core is validated over this repo's full ~11,302-name test corpus,
cross-checked against the independent Java name-parser oracle: 0 diffs (see
crates/nameparser-py/python/tests/test_parity.py and
docs/superpowers/findings/2026-07-11-phase4a-python-status.md).
Install
Not yet published to PyPI. Until then, build from source with maturin inside this repo's project-local venv:
python3 -m venv .venv && . .venv/bin/activate
pip install maturin
maturin develop --release -m crates/nameparser-py/Cargo.toml
maturin develop compiles the Rust cdylib and installs it into the active virtualenv as an
editable nameparser package (including the nameparser.pyi type stub and a py.typed
marker — this package is fully typed; see Editors / type checkers
below). Once published, the same package will install with:
pip install gbif-name-parser # → import nameparser
(The PyPI distribution name is gbif-name-parser — matching the Rust core crate on
crates.io, so it's one name across both registries — but the importable module stays
nameparser either way; see pyproject.toml.)
Usage
import nameparser
pn = nameparser.parse("Vulpes vulpes silaceus Miller, 1907")
print(pn.rank, pn.genus, pn.specific_epithet, pn.infraspecific_epithet) # SUBSPECIES Vulpes vulpes silaceus
print(pn.combination_authorship.authors, pn.combination_authorship.year) # ['Miller'] 1907
print(pn.to_dict()["type"]) # SCIENTIFIC — full dict, wire (JSON/Java) field names
results = nameparser.parse_all(["Abies alba", "Tobacco mosaic virus"]) # batch: never raises
print(results) # [ParsedName(...), None]
try:
nameparser.parse("Tobacco mosaic virus")
except nameparser.UnparsableNameError as e:
print(e.name_type, e.code, e.name) # OTHER VIRUS Tobacco mosaic virus
print(str(e)) # Unparsable OTHER name: Tobacco mosaic virus
Every one of ParsedName's 30 core fields is exposed as a Python property (snake_case, e.g.
specific_epithet, combination_authorship, published_in_year); enum-typed fields (rank,
code, type, state, and each element of notho) come across as plain SCREAMING_SNAKE_CASE
strings ("SPECIES", "ZOOLOGICAL", …) — the same convention the JSON/Java wire format uses —
not a Python enum.Enum. rank/code inputs to parse()/parse_all() accept those same
strings (or None). to_dict() (on both ParsedName and the nested Authorship) returns the
complete structure straight from the core's own serde::Serialize impl, keyed by the JSON/Java
wire field names (specificEpithet, not specific_epithet) — the escape hatch for anything a
typed getter doesn't surface, and the parity oracle the corpus test itself diffs against.
UnparsableNameError.name_type/.code/.name mirror Java's
org.gbif.nameparser.api.UnparsableNameException's getType()/getCode()/getName(); str(e)
is still exactly the core's own message, unchanged.
Editors / type checkers
nameparser.pyi (shipped inside the package, alongside a py.typed marker) gives Pyright/mypy/
your editor full attribute-level types for parse/parse_all/ParsedName/Authorship/
UnparsableNameError — no more "unknown attribute" noise on pn.specific_epithet or
e.name_type. It's hand-written (the compiled extension has no Python source for a stub
generator to read) and kept in sync by hand with src/lib.rs's getters; see its own module
docstring.
Native, no JDK required
This binding never starts a JVM and needs no java/JAVA_HOME on the machine that runs it —
unlike bindings/java (which requires JDK 22+ for java.lang.foreign) — because it compiles
directly against the Rust core, in-process, with PyO3 doing the Rust↔Python marshalling at the
Rust/CPython C-API level rather than crossing a JVM boundary at all. Performance-wise it
inherits the native CLI's batch-throughput profile (see the root BENCHMARKS.md):
there is no per-call FFM downcall or JSON re-serialization step the way the Java binding's
NameParserRust has, since parse()/parse_all() call nameparser::parse directly.
Development
. .venv/bin/activate
maturin develop --release -m crates/nameparser-py/Cargo.toml
pytest crates/nameparser-py/python/tests/ -v
Three test files under python/tests/:
test_api.py— unit tests for the binding surface itself (getters,to_dict(),parse_all()'s none-on-unparsable contract,UnparsableNameError's structured attributes).test_getter_consistency.py— checks every#[getter]agrees withto_dict()over a representative sample (a pathtest_parity.pyalone can't exercise, since it only ever callsto_dict()).test_parity.py— the corpus parity gate: diffsnameparser.parse(name).to_dict(), andUnparsableNameError's message/name_type/code, against an independent Java-oracle (or Rust-CLI-fallback) row for every one of the ~11,302 corpus names. Needs a JDK onPATH(falls back to the releasenameparser-clibinary if the Java shaded jar isn't available).
Build a wheel (not published) with:
maturin build --release -m crates/nameparser-py/Cargo.toml # → target/wheels/*.whl (git-ignored)
The wheel is abi3 (built against the stable Python C ABI, py39 floor) — one wheel per
platform, working across Python 3.9+, not one per Python minor version.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gbif_name_parser-0.1.0.tar.gz.
File metadata
- Download URL: gbif_name_parser-0.1.0.tar.gz
- Upload date:
- Size: 403.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e5b6eb446fb170f383bc09f12d728bb589c2b21b5a8017bd8f78af291cfb706
|
|
| MD5 |
730afba8c021d76828450971763d42a9
|
|
| BLAKE2b-256 |
53a1790df64b343bc44e09b2e1e0b570c3b19f9f76d8638edab03234900c334c
|
Provenance
The following attestation bundles were made for gbif_name_parser-0.1.0.tar.gz:
Publisher:
python-release.yml on gbif/name-parser-rust
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gbif_name_parser-0.1.0.tar.gz -
Subject digest:
3e5b6eb446fb170f383bc09f12d728bb589c2b21b5a8017bd8f78af291cfb706 - Sigstore transparency entry: 2169160895
- Sigstore integration time:
-
Permalink:
gbif/name-parser-rust@feb4d18add800ab3b0ee41babaea6ec3244d7797 -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/gbif
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-release.yml@feb4d18add800ab3b0ee41babaea6ec3244d7797 -
Trigger Event:
push
-
Statement type:
File details
Details for the file gbif_name_parser-0.1.0-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: gbif_name_parser-0.1.0-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 1.2 MB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dcca09cf18c2408098c7d0e22e1f2f02c767ccd6641d86d00f0c75c93126ae3a
|
|
| MD5 |
2295fdcd26e12624577777c3f7f23ba5
|
|
| BLAKE2b-256 |
e757fc525fbfd4e812fc375f4e3c9093adc11f33a8db64873b6b486722a3507d
|
Provenance
The following attestation bundles were made for gbif_name_parser-0.1.0-cp39-abi3-win_amd64.whl:
Publisher:
python-release.yml on gbif/name-parser-rust
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gbif_name_parser-0.1.0-cp39-abi3-win_amd64.whl -
Subject digest:
dcca09cf18c2408098c7d0e22e1f2f02c767ccd6641d86d00f0c75c93126ae3a - Sigstore transparency entry: 2169162205
- Sigstore integration time:
-
Permalink:
gbif/name-parser-rust@feb4d18add800ab3b0ee41babaea6ec3244d7797 -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/gbif
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-release.yml@feb4d18add800ab3b0ee41babaea6ec3244d7797 -
Trigger Event:
push
-
Statement type:
File details
Details for the file gbif_name_parser-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: gbif_name_parser-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.4 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d9980de675a7cfb0d4c96a8b2c184ec68a6663eba265ec8ccf27feff3ba54ac
|
|
| MD5 |
fff3561f5e322e1eca9245fa77ae3477
|
|
| BLAKE2b-256 |
79fd0e550dd4562935b367e724d6a0c72c02d9529b36fb7a44abe1a6ef726933
|
Provenance
The following attestation bundles were made for gbif_name_parser-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
python-release.yml on gbif/name-parser-rust
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gbif_name_parser-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
6d9980de675a7cfb0d4c96a8b2c184ec68a6663eba265ec8ccf27feff3ba54ac - Sigstore transparency entry: 2169161318
- Sigstore integration time:
-
Permalink:
gbif/name-parser-rust@feb4d18add800ab3b0ee41babaea6ec3244d7797 -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/gbif
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-release.yml@feb4d18add800ab3b0ee41babaea6ec3244d7797 -
Trigger Event:
push
-
Statement type:
File details
Details for the file gbif_name_parser-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: gbif_name_parser-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 1.4 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
343a1b72c286e22eaf22978ce4fa9b270e4a6b0d8c5d882e0bad147c2c90b255
|
|
| MD5 |
78bb6b8c0d734c1000331a500c996834
|
|
| BLAKE2b-256 |
52be50db10c11507b8fff1d612a07753961071ec5c96ab2776cc0a3586df82c7
|
Provenance
The following attestation bundles were made for gbif_name_parser-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
python-release.yml on gbif/name-parser-rust
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gbif_name_parser-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
343a1b72c286e22eaf22978ce4fa9b270e4a6b0d8c5d882e0bad147c2c90b255 - Sigstore transparency entry: 2169162087
- Sigstore integration time:
-
Permalink:
gbif/name-parser-rust@feb4d18add800ab3b0ee41babaea6ec3244d7797 -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/gbif
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-release.yml@feb4d18add800ab3b0ee41babaea6ec3244d7797 -
Trigger Event:
push
-
Statement type:
File details
Details for the file gbif_name_parser-0.1.0-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: gbif_name_parser-0.1.0-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.3 MB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15247940bc024b9b53da0b1db9da79352f056adcbb3b32e5f936dbd214a97e43
|
|
| MD5 |
83f1048a554fd0a8137036c2a32c518c
|
|
| BLAKE2b-256 |
1d248844ea9798705f1b28ca7e8b3f08be1aa3d1d96d207b655984231b490c97
|
Provenance
The following attestation bundles were made for gbif_name_parser-0.1.0-cp39-abi3-macosx_11_0_arm64.whl:
Publisher:
python-release.yml on gbif/name-parser-rust
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gbif_name_parser-0.1.0-cp39-abi3-macosx_11_0_arm64.whl -
Subject digest:
15247940bc024b9b53da0b1db9da79352f056adcbb3b32e5f936dbd214a97e43 - Sigstore transparency entry: 2169161679
- Sigstore integration time:
-
Permalink:
gbif/name-parser-rust@feb4d18add800ab3b0ee41babaea6ec3244d7797 -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/gbif
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-release.yml@feb4d18add800ab3b0ee41babaea6ec3244d7797 -
Trigger Event:
push
-
Statement type: