Skip to main content

Pydantic custom type for Chilean RUT validation and formatting

Project description

pydantic-type-chile-rut

CI codecov PyPI version Python versions License: MIT

A Pydantic custom type for Chilean RUT (Rol Único Tributario) validation and formatting.

Features

  • Comprehensive validation: Validates RUT format, length, and check digit
  • 🔧 Flexible input: Accepts RUTs with or without dots and hyphens
  • 📝 Multiple formats: Provides both compact and formatted output
  • 🏷️ Type-safe: Full Pydantic v2 integration with proper type hints
  • 🧪 Well-tested: Comprehensive test suite with 100% coverage
  • 🚀 High performance: Efficient validation using Pydantic's core schema

Installation

pip install pydantic-type-chile-rut

Or using uv:

uv add pydantic-type-chile-rut

Quick Start

from pydantic import BaseModel
from pydantic_type_chile_rut import RutNumber

class Person(BaseModel):
    name: str
    rut: RutNumber

# Create a person with a valid RUT
person = Person(name="Juan Pérez", rut="12.345.678-5")

print(person.rut)           # "12345678-5" (compact format)
print(person.rut.formatted) # "12.345.678-5" (with dots)
print(person.rut.number)    # 12345678 (numeric part)
print(person.rut.dv)        # "5" (check digit)

RUT Format Support

The library accepts RUTs in various formats:

from pydantic_type_chile_rut import RutNumber

# All these inputs are equivalent and valid:
valid_formats = [
    "12.345.678-5",    # Standard format with dots and hyphen
    "12345678-5",      # Without dots
    "123456785",       # Without dots or hyphen
    "12.345.678-5",    # With spaces (trimmed automatically)
]

# Case insensitive check digits:
rut_with_k = RutNumber.model_validate("15.345.678-k")  # -> "15345678-K"

RutNumber Properties

The RutNumber class provides several useful properties and methods:

from pydantic_type_chile_rut import RutNumber

rut = RutNumber(12345678, "5")

# Properties
print(rut.number)     # 12345678 (int)
print(rut.dv)         # "5" (str)
print(str(rut))       # "12345678-5" (compact format)

# Formatting methods
print(rut.formatted)   # "12.345.678-5" (property)
print(rut.with_dots()) # "12.345.678-5" (method)

# Representation
print(repr(rut))      # "RutNumber(number=12345678, dv='5')"

Validation Examples

Valid RUTs

from pydantic import BaseModel
from pydantic_type_chile_rut import RutNumber

class TestModel(BaseModel):
    rut: RutNumber

# These will all validate successfully:
valid_ruts = [
    "12.345.678-5",      # Standard format
    "15.345.678-K",      # With K check digit
    "1-9",               # Short RUT
    "0-0",               # Zero RUT (special case)
    "123456785",         # Without punctuation
    "00001234-3",        # With leading zeros (normalized)
]

for rut_str in valid_ruts:
    model = TestModel(rut=rut_str)
    print(f"{rut_str} -> {model.rut}")

Invalid RUTs

from pydantic import ValidationError

invalid_ruts = [
    "12345678-4",        # Wrong check digit
    "ABC",               # Not numeric
    "12.345.678-",       # Missing check digit
    "",                  # Empty string
    "123.456.789-0",     # Too long (> 9 digits)
    "12345678-X",        # Invalid check digit character
]

for rut_str in invalid_ruts:
    try:
        TestModel(rut=rut_str)
    except ValidationError as e:
        print(f"{rut_str} -> {e.errors()[0]['msg']}")

Integration with Pydantic Models

Basic Usage

from pydantic import BaseModel
from typing import Optional
from pydantic_type_chile_rut import RutNumber

class Employee(BaseModel):
    id: int
    name: str
    rut: RutNumber
    supervisor_rut: Optional[RutNumber] = None

employee = Employee(
    id=1,
    name="María González",
    rut="18.765.432-1",
    supervisor_rut="12.345.678-5"
)

# Serialization
employee_dict = employee.model_dump()
print(employee_dict)
# {
#     'id': 1,
#     'name': 'María González',
#     'rut': '18765432-1',
#     'supervisor_rut': '12345678-5'
# }

JSON Schema Generation

from pydantic import BaseModel
from pydantic_type_chile_rut import RutNumber

class Person(BaseModel):
    rut: RutNumber

# Generate JSON schema
schema = Person.model_json_schema()
print(schema)

Using with TypeAdapter

from pydantic import TypeAdapter
from pydantic_type_chile_rut import RutNumber

adapter = TypeAdapter(RutNumber)

# Validate single RUT
rut = adapter.validate_python("12.345.678-5")
print(f"Valid RUT: {rut.formatted}")

# Validate list of RUTs
ruts_adapter = TypeAdapter(list[RutNumber])
ruts = ruts_adapter.validate_python([
    "12.345.678-5",
    "15.345.678-K",
    "1-9"
])

Advanced Usage

Custom Validation

from pydantic import BaseModel, field_validator
from pydantic_type_chile_rut import RutNumber

class BusinessEntity(BaseModel):
    business_rut: RutNumber
    legal_rep_rut: RutNumber

    @field_validator('business_rut')
    @classmethod
    def validate_business_rut(cls, v):
        # Business RUTs in Chile typically have 8-9 digits
        if v.number < 50000000:
            raise ValueError('Business RUT seems too low')
        return v

entity = BusinessEntity(
    business_rut="96.511.760-1",
    legal_rep_rut="12.345.678-5"
)

Working with Databases

from pydantic import BaseModel
from sqlalchemy import Column, String, Integer
from pydantic_type_chile_rut import RutNumber

# SQLAlchemy model
class PersonDB:
    __tablename__ = 'persons'

    id = Column(Integer, primary_key=True)
    rut = Column(String(12))  # Store as "12345678-5"
    name = Column(String(100))

# Pydantic model for API
class PersonAPI(BaseModel):
    id: int
    rut: RutNumber
    name: str

    @classmethod
    def from_db(cls, db_person):
        return cls(
            id=db_person.id,
            rut=db_person.rut,  # Automatically validates
            name=db_person.name
        )

Check Digit Algorithm

The library implements the standard Chilean RUT check digit algorithm (modulo 11):

  1. Multiply each digit by weights [2, 3, 4, 5, 6, 7] from right to left, cycling
  2. Sum all products
  3. Calculate 11 - (sum % 11)
  4. If result is 11, use "0"; if 10, use "K"; otherwise use the number

Development

This project uses uv for dependency management and packaging.

Setup Development Environment

# Clone the repository
git clone https://github.com/flolas/pydantic-type-chile-rut.git
cd pydantic-type-chile-rut

# Install dependencies
uv sync --dev

# Install pre-commit hooks
uv run pre-commit install

# Run tests
uv run pytest

# Run tests with coverage
uv run pytest --cov=src/pydantic_type_chile_rut --cov-report=html

# Run linting and formatting
uv run pre-commit run --all-files

Project Structure

pydantic-type-chile-rut/
├── src/
│   └── pydantic_type_chile_rut/
│       ├── __init__.py
│       └── rut.py
├── tests/
│   ├── __init__.py
│   └── test_rut.py
├── .github/
│   └── workflows/
│       ├── ci.yml
│       └── release.yml
├── pyproject.toml
├── README.md
└── LICENSE

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Guidelines

  • Add tests for any new features
  • Ensure all tests pass
  • Follow the existing code style
  • Update documentation as needed

Testing

Run the full test suite:

uv run pytest tests/ -v

Run with coverage:

uv run pytest tests/ --cov=src/pydantic_type_chile_rut --cov-report=term-missing

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

See CHANGELOG.md for a history of changes.

Support

If you encounter any issues or have questions, please open an issue on GitHub.

Related Projects

Acknowledgments

  • Thanks to the Pydantic team for creating an excellent validation library
  • Inspired by various Chilean RUT validation implementations

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pydantic_type_chile_rut-1.0.1.tar.gz (11.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pydantic_type_chile_rut-1.0.1-py3-none-any.whl (7.2 kB view details)

Uploaded Python 3

File details

Details for the file pydantic_type_chile_rut-1.0.1.tar.gz.

File metadata

  • Download URL: pydantic_type_chile_rut-1.0.1.tar.gz
  • Upload date:
  • Size: 11.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for pydantic_type_chile_rut-1.0.1.tar.gz
Algorithm Hash digest
SHA256 2b8f2b102a53787cf7386ad86198d9b4efbb79f722c56430c326e4c509dec3e5
MD5 0437aeec5e7835cf2064d91686c81489
BLAKE2b-256 7bdad1d0c0f709b0046f536115519d507d66334c1e07fa991c330e9dcf5bfdcd

See more details on using hashes here.

Provenance

The following attestation bundles were made for pydantic_type_chile_rut-1.0.1.tar.gz:

Publisher: release.yml on flolas/pydantic-type-chile-rut

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pydantic_type_chile_rut-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for pydantic_type_chile_rut-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 79a3a78449fd338515c9837551c4a59aa5e934b7083d62f6db54dd082d5dd92c
MD5 c344a46a2a0e81a9604d5c1dee68ed35
BLAKE2b-256 9595d4b9d9983854611c7548dca466affe0faa5cfb4c737ec71df99ac86e2868

See more details on using hashes here.

Provenance

The following attestation bundles were made for pydantic_type_chile_rut-1.0.1-py3-none-any.whl:

Publisher: release.yml on flolas/pydantic-type-chile-rut

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page