Skip to content

API Reference

This page is the concise reference for the public Python surface you import. For the mental model behind these types, see Concepts.


import paxman
from paxman.capabilities import (
Country,
Currency,
Date,
Email,
IP,
ISBN,
Money,
Phone,
SIUnit,
URL,
)
from paxman.core.domain import Resolution
from paxman.core.errors import (
PaxmanError,
CapabilityError,
ContractError,
MultipleMentionsError,
RecognitionError,
ValidationError,
)

Paxman has no runtime dependencies. import paxman is side-effect free — nothing runs until you register and call canonicalize().


Registration tells the engine which capabilities exist. It must complete from one thread before the first canonicalize() call; afterwards the registry freezes and reads are safe from any thread.

FunctionSignatureWhat it does
paxman.register_all_shipped()() -> tuple[str, ...]Registers every capability shipped in this release. Idempotent by name. Returns the names newly registered by this call.
paxman.register_capability(cap)(cap: Capability) -> NoneRegisters one capability instance, e.g. Email(). Fails if the name already exists or the registry is frozen.
paxman.register_grammar(name, cls)(capability_name: str, grammar_cls: type[Grammar]) -> NoneRegisters a community grammar (see Extending). Must happen before the first call.
paxman.register_rule(name, cls)(capability_name: str, rule_cls: type[Rule]) -> NoneRegisters a community rule. Must happen before the first call.
# Quick exploration — everything
paxman.register_all_shipped()
# Explicit — only what you depend on
paxman.register_capability(Email())
paxman.register_capability(Date())

The sole entry point.

def canonicalize(text: str, contract: CapabilityContract) -> ExecutionResult
ParameterTypeDescription
textstrRaw input. One presumed mention per call (see Segmentation).
contractCapabilityContractCreated via SomeCapability.create_contract(...). Carries capability_name so no separate name argument is needed.

Returns ExecutionResult — always, for every domain outcome including missing or invalid input. Domain outcomes are statuses, not exceptions.

Raises

ExceptionCause
CapabilityErrorNo capability matches contract.capability_name
ContractErrorMalformed contract (unknown pinned_rules, unknown output_format, unknown semantics, missing required feature)
MultipleMentionsErrorTwo or more non-overlapping mentions resolved to different values — caller must split first
RecognitionErrorGrammar raised or returned a malformed match (rule, original_error)
ValidationErrorRule raised inside matches()/normalize() (rule, original_error)

MISSING / INVALID / AMBIGUOUS do not raise — they are ExecutionResult.status values (see Execution Result and Candidates & Ambiguity).


Batch scan — one ScanContext substrate pass, per-capability Mention records.

def scan(text: str, contracts: Sequence[CapabilityContract]) -> ScanResult
ParameterTypeDescription
textstrInput text to scan (may contain many mentions).
contractsSequence[CapabilityContract]One contract per capability to scan; each carries its suppress_common_words and other flags.

Returns ScanResult — per-capability mentions dict sharing one substrate.

Raises

ExceptionCause
TypeErrortext is not str or contracts is not a Sequence
CapabilityErrorA contract names an unregistered capability

The scan shares one ScanContext (word spans and lazy views) across all contracts, so querying many capabilities costs one substrate build. Suppression (suppress_common_words) is honored per-contract: a Country contract with suppress_common_words=True drops word-bounded hits like to → TO (Tonga) via COMMON_WORDS (67), while the same text scanned with False keeps them. For the honest F1 path on prose, scan() is the preferred successor to MultipleMentionsError on canonicalize() — see docs/user/migration.md and docs/recipes/segmentation.md.

import paxman
from paxman.capabilities.Country import Country
from paxman.core.errors import MultipleMentionsError
paxman.register_all_shipped()
contract = Country.create_contract()
# Prose with embedded values — the new honest path:
try:
result = paxman.canonicalize("Ship to United States please", contract)
except MultipleMentionsError:
# scan() shares one ScanContext substrate across all contracts in the batch
mentions = paxman.scan("Ship to United States please", [contract])
# mentions.mentions["country"] == [
# Mention(span=(5, 7), grammar="alpha2_recognition", notation=...),
# Mention(span=(8, 21), grammar="name_recognition", notation=...),
# ]
for m in mentions.mentions["country"]:
print(m.span, m.grammar, m.notation)

See Segmentation for when to use scan() vs caller-owned split-then-canonicalize.


Contracts — SomeCapability.create_contract()

Section titled “Contracts — SomeCapability.create_contract()”

Every capability exposes a keyword-only factory. Common parameters come first, capability-specific ones after.

contract = Email.create_contract(
# common — every capability
excluded_rules=(), # Sequence[str]
pinned_rules=None, # Sequence[str] | None — when not None, only these run
year=None, # int | None — only rules with publication_year <= year
output_format=None, # str | None — None / "default" / default / offered, else ContractError
extra_grammars=(), # tuple[str, ...] — opt-in community grammars
suppress_common_words=False, # bool — suppress word-bounded short-code hits in COMMON_WORDS (67)
# capability-specific — varies by capability
include_obfuscated=False, # example: Email only
)

The contract is a frozen dataclass — construct it, pass it, inspect it, but do not mutate it. See Contracts for the full common-plus-specific table.

output_format policy (identical for every capability)

Section titled “output_format policy (identical for every capability)”
  • None, "default", and the capability’s DEFAULT_OUTPUT_FORMAT all resolve to the default.
  • Any value in OFFERED_OUTPUT_FORMATS resolves to itself.
  • Anything else raises ContractError immediately. Validation never consults output_format.

Current defaults and offered alternatives:

CapabilityDefault (DEFAULT_OUTPUT_FORMAT)Offered (OFFERED_OUTPUT_FORMATS)
Countryalpha2alpha3, numeric, name
Currencycode(none — single format)
DateISOUS
DOIdoiurl
Emailemail(none)
IPip(none)
ISBNisbn13hyphenated
Moneycode_amountcompact
Phonee164rfc3966, split
SI Unitsymbol(none)
URLurl(none)
BICbicgrouped, bic11
Coordinatesdecimaliso6709, geo_uri, geojson_pair, dms, dm
ChemicalElementsymbolname
IBANelectronicpaper
ISSNhyphenatedcompact, urn
ISINisingrouped
ISNIisnicompact, urn
LEIleiurn
UNSPSCunspsclabeled, native
GTINgtin14native
CreditCardpangrouped
Languagebcp47alpha2, alpha3, alpha3-bib, name
MacAddresscolonhyphen, bare, cisco, eui64
MinorPlanetdesignationpacked
ORCIDorciduri, compact
Timezoneiana(none — single format)
UtcOffsetextendedbasic
UUIDhyphenatedcompact, braced, urn
Domainasciiunicode

The set of capabilities — and their offered formats — grows over time. Treat this table as the current release, not a closed list.

Capability-specific flag summary (current release)

Section titled “Capability-specific flag summary (current release)”
CapabilityFlagTypeDefaultPurpose
Emailinclude_obfuscatedboolFalseuser at domain dot com
Emailinclude_localhostboolTrueadmin@localhost
Countryinclude_localizedboolFalseCLDR multilingual names
Countryinclude_historicalboolFalseDeprecated names
Currencydefault_currencystr | NoneNoneResolve shared bare symbol ($) to this alpha-3 code
IPinclude_ipv6boolTrueIPv6
ISBNinclude_isbn10boolTrueLegacy ISBN-10
ISBNinclude_range_validationboolFalseRegistrant-range provenance
Languageinclude_localizedboolFalseCLDR localized display-name validation
Languageinclude_collectiveboolFalseISO 639-5 collective-code validation
Languageinclude_privateboolFalsePrivate-use subtag validation
GTINinclude_verifiedboolFalseVerified-by-GS1 liveness lookup
CreditCardinclude_brand_validationboolFalseBrand IIN/length membership
Moneydollar_sign_currencystr | NoneNoneResolve bare $ amount to this alpha-3 code
Moneyprecisionstr"strict"strict / truncate / round for over-precision amounts
Phonedefault_countrystr | NoneNoneInterpret national numbers as if in this alpha-2 country
SI Unitallow_split_word_prefixesboolFalsekilo gram → kg
SI Unitallow_multi_solidusboolFalsekg/m/s preserved
Datetwo_digit_base_yearint | NoneNoneBase for 2-digit year expansion
Timezoneinclude_systemvboolFalseValidate SystemV zones (EST5EDT and kin)
commonsuppress_common_wordsboolFalsesuppress word-bounded short-code hits in COMMON_WORDS (67)

Validation: default_currency / dollar_sign_currency must be uppercase alpha-3; default_country must be uppercase alpha-2; precision must be one of the three values — otherwise ContractError at construction time.


@dataclass(frozen=True)
class ExecutionResult:
status: Resolution # MISSING | INVALID | SUCCESS | AMBIGUOUS
canonicalized_value: str | None # str on SUCCESS, None otherwise
candidates: tuple[Candidate, ...] # all validated evidence, deduplicated
contract: CapabilityContract # the contract you passed in
version_stamp: VersionStamp # .paxman_version
span: tuple[int, int] | None # [start, end) of resolved value on SUCCESS, else None
suppressed_count: int = 0 # hits dropped by suppress_common_words (ADR-0009 §16, #122)
suppressed_spans: tuple[tuple[int, int], ...] = () # [start, end) of each suppressed hit
@dataclass(frozen=True)
class Candidate:
value: str
recognition_rule: str # grammar name, e.g. "standard_recognition"
validation_rule: str # rule name, e.g. "Section 3.4.1-addr-spec"
span: tuple[int, int] | None # half-open [start, end) in the input
provenance: tuple[
Provenance, ...
] # one or more authority citations (read-only property)
@dataclass(frozen=True)
class Provenance:
authority: str # "IETF", "ISO", "BIPM", "WHATWG", "CLDR", ...
specification_name: str # "RFC 5322", "ISO 3166-1", ...
kind: str # "specification" / "standard" / ...
reference_url: str
version: str | None
lifecycle: str # "active" / "deprecated" / ...
publication_year: int
@dataclass(frozen=True)
class VersionStamp:
paxman_version: str
recognition_revision: str # kernel recognition revision (default "0")
class Resolution(Enum):
MISSING = "missing"
INVALID = "invalid"
SUCCESS = "success"
AMBIGUOUS = "ambiguous"

Reading the result (see also Execution Result):

from paxman.core.domain import Resolution
if result.status == Resolution.SUCCESS:
value = result.canonicalized_value # str, span is set
else:
# MISSING / INVALID / AMBIGUOUS — no single value, span is None
# inspect result.candidates and their provenance/spans
...

span semantics: on SUCCESS it is the span of the single resolved value; on AMBIGUOUS use each candidate.span; on MISSING/INVALID it is None and candidates is empty.

suppressed_count / suppressed_spans: populated whenever suppress_common_words=True suppression fires, on any status (ADR-0009 §16, A0 #122) — 0/() when the flag is off or nothing was suppressed. Spans are in sorted positional order. A whole-input suppressible hit is never suppressed (A0 exemption), so canonicalize("to", Country suppress on) → SUCCESS "TO" with 0/(), while canonicalize("in/", …) → MISSING with suppressed_count == 1, suppressed_spans == ((0, 2),).


All exceptions inherit from PaxmanError. See Errors for handling patterns.

ExceptionSignal typeTypical cause
CapabilityErrorsetupUnknown capability, duplicate name, registry already frozen
ContractErrorsetupBad pinned_rules, bad output_format, unknown semantics, missing required feature, bad default_currency/default_country/precision
MultipleMentionsErrorusageTwo separate mentions with different values in one call — split first
RecognitionErrorinternal bugGrammar raised or returned a bad span/raw_text. Fields: rule, original_error (None on structural failure)
ValidationErrorinternal bugRule raised inside matches()/normalize(). Fields: rule, original_error

Statuses vs exceptions: statuses are domain answers returned inside ExecutionResult; exceptions mean the call was not valid to attempt. Catch exceptions at setup and at the outer edge of a batch loop; branch on statuses in normal flow.


Quick lookup — choose the right capability

Section titled “Quick lookup — choose the right capability”
Kind of text you haveCapability to useFactory
Email addressesEmailEmail.create_contract(...)
DatesDateDate.create_contract(...)
Country codes or namesCountryCountry.create_contract(...)
Currency codes / symbols / names (no amount)CurrencyCurrency.create_contract(...)
IP addressesIPIP.create_contract(...)
ISBNsISBNISBN.create_contract(...)
Money amounts with currencyMoneyMoney.create_contract(...)
Phone numbersPhonePhone.create_contract(...)
SI unit expressionsSI UnitSIUnit.create_contract(...)
Absolute URLs / IRIsURLURL.create_contract(...)
Business identifier codesBICBIC.create_contract(...)
WGS 84 coordinatesCoordinatesCoordinates.create_contract(...)
Chemical elementsChemicalElementChemicalElement.create_contract(...)
Bank account numbersIBANIBAN.create_contract(...)
Serial identifiersISSNISSN.create_contract(...)
Securities identification numbersISINISIN.create_contract(...)
Researcher/organization identifiersISNIISNI.create_contract(...)
Product/service codesUNSPSCUNSPSC.create_contract(...)
Legal entity identifiersLEILEI.create_contract(...)
Trade item identifiersGTINGTIN.create_contract(...)
Payment card numbers (PANs)CreditCardCreditCard.create_contract(...)
Language identifiersLanguageLanguage.create_contract(...)
MAC addressesMacAddressMacAddress.create_contract(...)
Researcher identifiersORCIDORCID.create_contract(...)
Time zone identifiersTimezoneTimezone.create_contract(...)
UTC offset valuesUtcOffsetUtcOffset.create_contract(...)
UUIDsUUIDUUID.create_contract(...)
Digital object identifiersDOIDOI.create_contract(...)
HostnamesDomainDomain.create_contract(...)

New capabilities appear in minor releases — check paxman.capabilities for the current set. Each per-capability guide under Capabilities details its recognized forms, output formats, contract flags, and provenance.