Skip to main content

nieve

Validate and format Chilean RUT values in Python.

The core API matches nieve for TypeScript and uses snake_case names. Both packages share one set of fixtures, including a generated conformance suite that fails CI when the two implementations disagree, and both are released with the same version number. The TypeScript-only formatPartial helper is for progressive browser input and is intentionally omitted here.

Motivation

The last releases of the legacy JavaScript libraries rut.js and rutjs were published in 2021 and 2013, respectively, and they still have open issues. This package brings strict validation and structured issues to Python. See the agent reference for complete contracts and recipes.

Install

pip install nieve

Usage

Examples import the package as rut so each call reads on its own.

import nieve as rut

value = rut.parse("21.272.789-K")
# "21272789K"

rut.format(value)                          # "21.272.789-K"
rut.format(value, style="plain")           # "21272789-K"
rut.format(value, verifier_case="lower")   # "21.272.789-k"

rut.safe_parse("21.272.789-0", "en")
# SafeParseFailure(
#     success=False,
#     issue=VerifierIssue(
#         kind="verifier",
#         message='RUT verifier does not match. Replace "0" with "K".',
#         input="21.272.789-0",
#         expected="K",
#         received="0",
#     ),
# )

rut.is_rut("21272789k")  # True (the TypeScript name is `is`)

rut.clean("0021.272.789-k")                # "21272789K" (does not validate)
rut.get_verifier("21.272.789")             # "K"
rut.compare("21.272.789-K", "21272789K")   # True

Accepted input

21.272.789-K
21.272.789K
21272789-K
21272789K
21.272.789-k
  • Input must be a string.
  • Surrounding whitespace is ignored. Whitespace inside the value is not.
  • The body contains 7 or 8 digits and does not start with zero.
  • Dots are either all present in groups of three or entirely absent: 21.272789-K is rejected.
  • The hyphen before the verifier is optional.
  • k is accepted in either case.

The 7-digit floor is deliberate: it rejects modulo-11 false positives in short input such as 17353. It also rejects very low real RUT values and test values such as 1-9, which report length.

Issue kinds

safe_parse returns one issue, and each kind means one thing:

kind When
type Input is not a string.
format The syntax is not a RUT: stray characters, mixed or misplaced separators, a leading zero.
length The syntax is valid but the body does not contain 7 or 8 digits. Carries body_length.
verifier The size is valid but the verifier does not match. Carries expected and received.

Narrow on the concrete dataclass or on kind:

from nieve import VerifierIssue, safe_parse

result = safe_parse("21.272.789-0")

if not result.success and isinstance(result.issue, VerifierIssue):
    result.issue.expected  # "K"

Stored values

format accepts anything parse accepts and raises RutError for anything else, so a canonical value read back from storage formats directly:

stored = "21272789K"

rut.format(stored)  # "21.272.789-K"

With Pydantic

parse raises RutError, a ValueError subclass. Use it directly with AfterValidator:

from typing import Annotated
from pydantic import AfterValidator, BaseModel
from nieve import parse

class User(BaseModel):
    national_id: Annotated[str, AfterValidator(parse)]

user = User(national_id="21.272.789-K")
user.national_id  # "21272789K"

API

API Purpose
parse(input, language="es") Validate input. Return the canonical RUT or raise RutError.
safe_parse(input, language="es") Validate input without raising. Return a structured result.
is_rut(input) Return whether the input is valid.
format(value, *, style="dotted", verifier_case="upper") Format a RUT. Validates first and raises RutError for invalid input.
clean(input) Normalize input without validating it. The output is untrusted.
compare(left, right) Return whether two inputs are the same RUT.
get_verifier(body) Calculate the verifier for a valid body. Return None for an invalid body.

style is "dotted" or "plain". verifier_case is "upper" or "lower".

Errors use Spanish (es) by default. Pass en as the second argument to parse or safe_parse for English messages.

compare returns False when either input is invalid, so it cannot distinguish "different" from "invalid". Use safe_parse when that difference matters.

Exported names: Rut, Language, RutError, RutIssue, RutIssueKind, TypeIssue, FormatIssue, LengthIssue, VerifierIssue, SafeParseResult, SafeParseSuccess, SafeParseFailure, Style, VerifierCase.

Development

uv sync --extra dev
uv run pytest
uv run mypy
uv run ruff check .

License

MIT

Release files for nieve 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nieve 1.0.0
File Size Uploaded
nieve-1.0.0.tar.gz 7.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nieve 1.0.0
File Interpreter ABI Platform
nieve-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 17.9 kB

Release files / nieve-1.0.0.tar.gz

Download URL nieve-1.0.0.tar.gz
Size 7.6 kB
Tags Source
SHA-256 checksum
How to use checksums
fcad4a9d994dbf9fe8d89a7da2a41b48803692a3590a25e37f1f5a2afde11891
BLAKE2b-256 checksum
How to use checksums
c8b8732fceabf5a8c02cc3fcfb46d2eb3655b7274b28fb3bf170b8c81fae17f3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / nieve-1.0.0-py3-none-any.whl

Download URL nieve-1.0.0-py3-none-any.whl
Size 10.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7682f07ed6d850433f1982d2a9698972d3c5cfe9505fd6fdc0cb47257e21e057
BLAKE2b-256 checksum
How to use checksums
0a29e01d6c8227ceefe7ee686be682be65d2a3326f9226649389faefbe88d2b1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page