Spain validator plugin for International URNs
Project description
International URNs - Spain Plugin
A comprehensive plugin for International URNs that provides validators and generators for Spanish identity documents and administrative codes.
Requirements
- Python 3.11 or higher
- international-urns 1.0.0rc3 or higher
- Pydantic 2.0+ (optional, for Pydantic integration)
- Faker 18.0+ (optional, for Faker integration)
Installation
# Basic installation
pip install international-urns-es
# With Pydantic integration
pip install international-urns-es[pydantic]
# With Faker integration
pip install international-urns-es[faker]
# With all optional dependencies
pip install international-urns-es[all]
Supported Documents
This plugin validates and generates the following Spanish document types:
- DNI - Documento Nacional de Identidad (National Identity Document)
- NIE - Número de Identidad de Extranjero (Foreigner Identity Number)
- NIF - Número de Identificación Fiscal (Tax Identification Number)
- CIF - Código de Identificación Fiscal (Company Tax Code)
- DIR3 - Directorio Común de unidades y oficinas (Common Directory of Administrative Units)
- NSS - Número de la Seguridad Social (Social Security Number)
- License Plates - Matrículas de vehículos (Vehicle registration plates)
Quick Start
Validation
import international_urns as iurns
# Validate a DNI
dni_validator = iurns.get_validator('es', 'dni')
result = dni_validator('urn:es:dni:12345678Z')
print(result) # urn:es:dni:12345678Z
# Validate a NIE
nie_validator = iurns.get_validator('es', 'nie')
result = nie_validator('urn:es:nie:X1234567L')
print(result) # urn:es:nie:X1234567L
# Validate a license plate
plate_validator = iurns.get_validator('es', 'plate')
result = plate_validator('urn:es:plate:1234BBC')
print(result) # urn:es:plate:1234BBC
Generation
import international_urns as iurns
# Generate a random valid DNI
dni_generator = iurns.get_generator('es', 'dni')
dni_urn = dni_generator()
print(dni_urn) # urn:es:dni:43335678K (random)
# Generate a random valid CIF
cif_generator = iurns.get_generator('es', 'cif')
cif_urn = cif_generator()
print(cif_urn) # urn:es:cif:B12345670 (random)
# Direct import also works
from international_urns_es import generate_dni, generate_nie
dni_urn = generate_dni()
nie_urn = generate_nie()
Document Types Reference
DNI (Documento Nacional de Identidad)
The DNI is the national identity document for Spanish citizens.
Format: 8 digits + 1 check letter
Examples:
12345678Z00000000T99999999R
URN Format:
urn:es:dni:12345678Z
Usage:
import international_urns as iurns
validator = iurns.get_validator('es', 'dni')
# Valid DNI
try:
result = validator('urn:es:dni:12345678Z')
print(f"Valid: {result}")
except ValueError as e:
print(f"Invalid: {e}")
Validation Rules:
- Must be exactly 8 digits followed by 1 letter
- Check letter is calculated using modulo 23 algorithm
- Case-insensitive for URN scheme, country, and document type
- Value preserves original case
NIE (Número de Identidad de Extranjero)
The NIE is the identification number for foreign nationals residing in Spain.
Format: Letter (X, Y, or Z) + 7 digits + 1 check letter
Examples:
X1234567LY0000000ZZ9999999R
URN Format:
urn:es:nie:X1234567L
Usage:
import international_urns as iurns
validator = iurns.get_validator('es', 'nie')
result = validator('urn:es:nie:X1234567L')
Validation Rules:
- Prefix must be X, Y, or Z
- Followed by exactly 7 digits
- Check letter calculated using same algorithm as DNI (with prefix conversion: X→0, Y→1, Z→2)
NIF (Número de Identificación Fiscal)
The NIF is the tax identification number for individuals in Spain. It accepts both DNI and NIE formats.
Format: DNI format (8 digits + letter) or NIE format (letter + 7 digits + letter)
Examples:
12345678Z(DNI format)X1234567L(NIE format)
URN Format:
urn:es:nif:12345678Z
urn:es:nif:X1234567L
Usage:
import international_urns as iurns
validator = iurns.get_validator('es', 'nif')
# DNI format
result1 = validator('urn:es:nif:12345678Z')
# NIE format
result2 = validator('urn:es:nif:X1234567L')
Validation Rules:
- Accepts both DNI and NIE formats
- Validates check letter for both formats
CIF (Código de Identificación Fiscal)
The CIF is the tax identification code for Spanish companies and organizations.
Format: 1 organization letter + 7 digits + 1 check character (letter or digit)
Organization Type Letters:
- A - Sociedades Anónimas (Public Limited Companies)
- B - Sociedades de Responsabilidad Limitada (Private Limited Companies)
- C - Sociedades Colectivas (General Partnerships)
- D - Sociedades Comanditarias (Limited Partnerships)
- E - Comunidades de Bienes (Communities of Property)
- F - Sociedades Cooperativas (Cooperatives)
- G - Asociaciones (Associations)
- H - Comunidades de Propietarios (Homeowner Associations)
- J - Sociedades Civiles (Civil Partnerships)
- N - Entidades Extranjeras (Foreign Entities)
- P - Corporaciones Locales (Local Corporations)
- Q - Organismos Autónomos (Autonomous Bodies)
- R - Congregaciones e Instituciones Religiosas (Religious Organizations)
- S - Órganos de la Administración del Estado (State Administration Bodies)
- V - Otros tipos no definidos (Other Undefined Types)
- W - Establecimientos permanentes de entidades no residentes (Permanent Establishments)
Examples:
A12345674(SA - Sociedad Anónima, check digit is number)B01234566(SL - Sociedad Limitada, check digit is number)N1234567J(Foreign entity - check digit is letter)
URN Format:
urn:es:cif:A12345674
Usage:
import international_urns as iurns
validator = iurns.get_validator('es', 'cif')
result = validator('urn:es:cif:A12345674')
Validation Rules:
- Organization types N, P, Q, R, S, W must have a letter as check digit
- Organization types A, B, E, H must have a number as check digit
- Other types can have either
- Check digit calculated using weighted sum algorithm
DIR3 (Directorio Común)
DIR3 codes identify administrative units and offices in the Spanish Public Administration.
Format: 1-2 letters + 8 digits
Administration Level Codes:
- A - Administración del Estado (State Administration)
- C - Comunidad Autónoma (Autonomous Community)
- L - Administración Local (Local Administration)
- E - Otras Entidades (Other Entities)
Examples:
A01002844(State administration unit)LA0003516(Local administration unit)E00003801(Other entity)
URN Format:
urn:es:dir3:A01002844
Usage:
import international_urns as iurns
validator = iurns.get_validator('es', 'dir3')
result = validator('urn:es:dir3:A01002844')
Validation Rules:
- Must be 9-10 characters total
- First 1-2 characters must be letters indicating administration level
- Remaining 8 characters must be digits
- First letter must be A, C, L, or E
NSS (Número de la Seguridad Social)
The NSS is the Social Security Number used in Spain.
Format: 12 digits, optionally formatted with slashes
Structure:
- First 2 digits: Province code (01-52 or special codes 66-99)
- Next 8 digits: Sequential number
- Last 2 digits: Check digits (calculated using modulo 97)
Examples:
281234567840(without slashes)28/12345678/40(with slashes)
URN Format:
urn:es:nss:281234567840
urn:es:nss:28/12345678/40
Usage:
import international_urns as iurns
validator = iurns.get_validator('es', 'nss')
# Without slashes
result1 = validator('urn:es:nss:281234567840')
# With slashes
result2 = validator('urn:es:nss:28/12345678/40')
Validation Rules:
- Must be exactly 12 digits
- Province code must be 01-52 (Spanish provinces) or 66-99 (special codes)
- Check digits validated using modulo 97 algorithm
- Accepts format with or without slashes
License Plates (Matrículas)
Spanish vehicle license plates. Supports current, historical, and special formats.
Current Format (since 2000): 4 digits + 3 consonants (no vowels)
Old Format (1971-2000): 1-2 province letters + 4 digits + 1-2 letters
Special Formats: Diplomatic (CD), Consular (CC), Foreign (E), etc.
Examples:
Current format:
1234BBC0000ZZZ9999DFG
Old format:
M1234AB(Madrid)B5678XY(Barcelona)PM9012CD(Palma de Mallorca)
Special format:
CD1234(Diplomatic)CC12345(Consular)E12345(Foreign)
URN Format:
urn:es:plate:1234BBC
urn:es:plate:M1234AB
urn:es:matricula:1234BBC
Usage:
import international_urns as iurns
validator = iurns.get_validator('es', 'plate')
# Current format
result1 = validator('urn:es:plate:1234BBC')
# Old format
result2 = validator('urn:es:plate:M1234AB')
# With spaces or hyphens (automatically normalized)
result3 = validator('urn:es:plate:1234 BBC')
result4 = validator('urn:es:plate:M-1234-AB')
Validation Rules:
Current format:
- Must be 4 digits + 3 consonants
- Allowed consonants: B, C, D, F, G, H, J, K, L, M, N, P, R, S, T, V, W, X, Y, Z
- No vowels (A, E, I, O, U), Ñ, or Q allowed
Old format:
- Province code must be valid (M, B, MA, PM, etc.)
- Followed by 4 digits
- Ending with 1-2 letters
Special format:
- Recognized prefixes: CD, CC, E, ET, CMD, DGP, MF, MMA, PMM, CNP
- Followed by 4-5 digits
Pydantic Integration
All validators work seamlessly with Pydantic v2 using AfterValidator annotations.
Option 1: Pre-defined Type Aliases (Recommended)
The plugin provides convenient pre-defined type aliases in the integrations.pydantic module:
from pydantic import BaseModel
from international_urns_es.integrations.pydantic import DNI_URN, CIF_URN, PLATE_URN
class Person(BaseModel):
name: str
dni: DNI_URN
class Company(BaseModel):
name: str
cif: CIF_URN
vehicles: list[PLATE_URN]
# Usage
person = Person(name="John Doe", dni="urn:es:dni:12345678Z")
company = Company(
name="Example SL",
cif="urn:es:cif:B01234566",
vehicles=["urn:es:plate:1234BBC", "urn:es:plate:5678DFG"]
)
Available type aliases: DNI_URN, NIE_URN, NIF_URN, CIF_URN, DIR3_URN, NSS_URN, PLATE_URN, MATRICULA_URN
Option 2: Using the Registry Interface
You can also create type aliases directly using the registry:
from typing import Annotated
import international_urns as iurns
from pydantic import BaseModel
from pydantic.functional_validators import AfterValidator, BeforeValidator
# Create type aliases using validators directly from the registry
DNI_URN = Annotated[str, AfterValidator(iurns.get_validator("es", "dni"))]
CIF_URN = Annotated[str, AfterValidator(iurns.get_validator("es", "cif"))]
# Type alias with both BeforeValidator and AfterValidator
DNI_URN_NORMALIZED = Annotated[
str,
BeforeValidator(str.strip), # Built-in normalization
AfterValidator(iurns.get_validator("es", "dni")),
]
# Use in models
class Person(BaseModel):
name: str
dni_urn: DNI_URN
class Company(BaseModel):
name: str
cif_urn: CIF_URN
class Employee(BaseModel):
name: str
dni_urn: DNI_URN_NORMALIZED # Strips whitespace before validation
# Usage
person = Person(name="John Doe", dni_urn="urn:es:dni:12345678Z")
company = Company(name="Example SL", cif_urn="urn:es:cif:B01234566") # SL uses B prefix
employee = Employee(name="Jane Doe", dni_urn=" urn:es:dni:12345678Z ") # Auto-strips
Advanced Pydantic Examples
Multiple validators in one model:
# Define additional validators using registry
PLATE_URN = Annotated[str, AfterValidator(iurns.get_validator("es", "plate"))]
class SpanishEntity(BaseModel):
name: str
dni_urn: DNI_URN | None = None
cif_urn: CIF_URN | None = None
plate_urn: PLATE_URN | None = None
# Person with DNI and vehicle
person = SpanishEntity(
name="John Doe",
dni_urn="urn:es:dni:12345678Z",
plate_urn="urn:es:plate:1234BBC"
)
List validation:
class CompanyFleet(BaseModel):
company_name: str
cif_urn: CIF_URN
vehicles: list[PLATE_URN]
# SL companies use B prefix
fleet = CompanyFleet(
company_name="Transport SL",
cif_urn="urn:es:cif:B01234566",
vehicles=["urn:es:plate:1234BBC", "urn:es:plate:5678DFG"]
)
Faker Integration
The plugin provides a Faker provider for generating random valid Spanish URN data for testing purposes.
from faker import Faker
from international_urns_es.integrations.faker import SpanishURNProvider
# Create a Faker instance and add the provider
fake = Faker()
fake.add_provider(SpanishURNProvider)
# Generate random Spanish URNs
dni = fake.dni_urn()
print(dni) # urn:es:dni:43335678K (random)
nie = fake.nie_urn()
print(nie) # urn:es:nie:Y1234567M (random)
cif = fake.cif_urn()
print(cif) # urn:es:cif:B12345670 (random)
plate = fake.plate_urn()
print(plate) # urn:es:plate:5678DFG (random)
Available Faker Methods
The SpanishURNProvider provides the following methods:
dni_urn()- Generate a random DNI URNnie_urn()- Generate a random NIE URNnif_urn()- Generate a random NIF URN (DNI or NIE format)cif_urn()- Generate a random CIF URNdir3_urn()- Generate a random DIR3 URNnss_urn()- Generate a random NSS URNplate_urn()- Generate a random license plate URNmatricula_urn()- Generate a random license plate URN (alternative name)
Integration with Pydantic and Faker
Combine both integrations for powerful test data generation:
from faker import Faker
from pydantic import BaseModel
from international_urns_es.integrations.faker import SpanishURNProvider
from international_urns_es.integrations.pydantic import DNI_URN, CIF_URN
# Setup Faker
fake = Faker()
fake.add_provider(SpanishURNProvider)
# Define Pydantic model
class Person(BaseModel):
name: str
dni: DNI_URN
class Company(BaseModel):
name: str
cif: CIF_URN
# Generate random valid test data
person = Person(name=fake.name(), dni=fake.dni_urn())
company = Company(name=fake.company(), cif=fake.cif_urn())
print(person) # name='John Doe' dni='urn:es:dni:43335678K'
print(company) # name='Example SL' cif='urn:es:cif:B12345670'
Development
Setup
# Clone the repository
git clone https://gitlab.com/Kencho1/international-urns-es.git
cd international-urns-es
# Create virtual environment with uv
uv venv
# Install dependencies with dev extras
uv pip install -e ".[dev]"
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=international_urns_es --cov-report=html
# Run specific test file
pytest tests/test_dni.py
# Run with verbose output
pytest -v
Code Quality
# Run ruff linter
ruff check .
# Run ruff formatter
ruff format .
# Run mypy type checker
mypy international_urns_es
Contributing
Contributions are welcome! Please ensure:
- All tests pass
- Code passes ruff and mypy checks
- New validators include comprehensive tests
- Documentation is updated
License
MIT License
Links
References
Official Documentation
- DNI - Spanish National ID
- NIE - Foreigner ID
- Seguridad Social - Social Security
- DIR3 - Administrative Directory
- DGT - Vehicle Plates
Algorithm References
- DNI/NIE check letter calculation uses modulo 23
- CIF check digit uses weighted sum algorithm
- NSS check digits use modulo 97
- License plate formats follow Spanish regulations from different eras
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 Distribution
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 international_urns_es-1.0.0rc2.tar.gz.
File metadata
- Download URL: international_urns_es-1.0.0rc2.tar.gz
- Upload date:
- Size: 17.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c0dac4a2a48d4c53713c8cea82e090010908c327617a53f779d7110a86f2cb9
|
|
| MD5 |
48d8d365a78a5786391477cf9ff8caf6
|
|
| BLAKE2b-256 |
b100fc0490d7549391c5bfd8e6cabe772c98efe3c5003a222b2d49c6dcad0085
|
File details
Details for the file international_urns_es-1.0.0rc2-py3-none-any.whl.
File metadata
- Download URL: international_urns_es-1.0.0rc2-py3-none-any.whl
- Upload date:
- Size: 28.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0b2816430569b65991189098ee9d0008516ed49ca616f0f5f462766d5547644
|
|
| MD5 |
caa49ce4cf077d35207e1c597764adc3
|
|
| BLAKE2b-256 |
8f5f7a21240d51a09742c6a1864855c0c9075a1a5cf8566e0ff195ce09499396
|