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-Kis rejected. - The hyphen before the verifier is optional.
kis 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)
| File | Size | Uploaded | |
|---|---|---|---|
| nieve-1.0.0.tar.gz | 7.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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}
|