Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ar-validators

Offline validation of Argentine identity numbers

English · Español


English

What it is

Offline validation of Argentine identity numbers. Zero dependencies, no network calls.

from ar_validators import validate_cuit

result = validate_cuit("20-00000000-1")

result.valid              # True
result.value              # "20000000001"
result.metadata["type"]   # "persona_fisica_masculino"

bad = validate_cuit("20-00000000-0")
bad.valid                 # False
bad.errors                # ["invalid check digit: expected 1, got 0"]

Why

Argentine identity numbers use checksum algorithms that are easy to get subtly wrong. The CUIT check digit has two special cases that most snippets skip. The CBU carries two independent check digits with different weight tables, and one of those weights is a 9 that gets mistyped as a 1 often enough that a buggy validator still passes casual testing — it only diverges when a specific digit is non-zero.

This library implements them correctly, offline, with no external calls.

What it validates

Function Input What it checks
validate_cuit CUIT / CUIL 11 digits, known prefix, modulo 11 check digit
validate_cuil CUIL same, and rejects legal-entity prefixes
validate_cbu CBU 22 digits, two independent modulo 10 check digits
validate_dni DNI 7–8 digits, plausible range (no checksum exists)
validate_patente License plate pre-Mercosur and both Mercosur formats
validate_cpa Postal code legacy 4-digit and current CPA, province letter

Installation

pip install ar-validators

Requires Python 3.9 or newer. Nothing else.

Usage

Every validator takes the number in any common written form — hyphens, dots and spaces are stripped before checking.

from ar_validators import (
    validate_cuit, validate_cuil, validate_cbu,
    validate_dni, validate_patente, validate_cpa,
)

validate_cuit("20000000001").valid        # True
validate_cuit("20 00000000 1").valid      # True

validate_cuil("30000000007").valid        # False — company prefix
validate_cuil("30000000007").errors
# ["prefix '30' belongs to a legal entity; a CUIL is issued only to natural persons"]

cbu = validate_cbu("0075305826018159083016")
cbu.metadata["bank_code"]                 # "007"
cbu.metadata["branch_code"]               # "5305"

validate_dni("12.345.678").value          # "12345678"

validate_patente("AB123CD").metadata      # format "mercosur", vehicle_type "auto"
validate_patente("A123BC").metadata       # format "mercosur", vehicle_type "moto"
validate_patente("ABC123").metadata       # format "pre_mercosur", vehicle_type None

validate_cpa("C1043AAZ").metadata["province"]   # "Ciudad Autónoma de Buenos Aires"
validate_cpa("1043").metadata["format"]         # "legacy"

Formatting

from ar_validators import format_cuit, format_cbu, format_dni

format_cuit("20000000001")    # "20-00000000-1"
format_cbu("0075305826018159083016")
                              # "00753058 26018159083016"
format_dni("12345678")        # "12.345.678"

Formatters return None when the input has the wrong number of digits. They do not check the checksum — validate first if that matters.

Taxpayer type

from ar_validators import cuit_type

cuit_type("20000000001")   # "persona_fisica_masculino"
cuit_type("27000000006")   # "persona_fisica_femenino"
cuit_type("30000000007")   # "persona_juridica"

Validation results

Every validator returns a frozen ValidationResult:

Field Type Meaning
valid bool True when every check passed
value str The normalized input — digits only, or canonical uppercase for plates and postal codes
errors list[str] Why it failed. Empty when valid
metadata dict Information derived from a valid input. Empty when invalid

The result is truthy when valid, so it reads naturally in a conditional:

if validate_cuit(user_input):
    ...

Test data generation

Putting a real CUIT in a test fixture means putting a real person's tax ID in your repository. Use the generators instead — they produce numbers with correct check digits that belong to nobody:

from ar_validators import generate_cuit, generate_cbu

generate_cuit()                  # random prefix
generate_cuit(prefix="27")       # specific prefix
generate_cbu(bank_code="007")    # specific bank

import random
generate_cuit(rng=random.Random(42))   # reproducible

Notes

Every number shown in this README is synthetic. The CUITs use an all-zero base, which is never issued, and the CBU came out of generate_cbu. None of them belongs to a real person or account.

This library validates format and checksums only. It does not verify whether a number is registered with any government agency. A CUIT that passes here is well-formed; whether it was ever issued, and to whom, is a question only ARCA can answer.

DNI numbers carry no check digit at all, so validate_dni can do no more than confirm the shape and a plausible range.

License

MIT


Español

Qué es

Validación offline de números de identidad argentinos. Cero dependencias, sin llamadas de red.

from ar_validators import validate_cuit

result = validate_cuit("20-00000000-1")

result.valid              # True
result.value              # "20000000001"
result.metadata["type"]   # "persona_fisica_masculino"

bad = validate_cuit("20-00000000-0")
bad.valid                 # False
bad.errors                # ["invalid check digit: expected 1, got 0"]

Por qué existe

Los números de identidad argentinos usan algoritmos de checksum fáciles de implementar mal de maneras sutiles. El dígito verificador del CUIT tiene dos casos especiales que la mayoría de los snippets se saltea. El CBU lleva dos dígitos verificadores independientes con tablas de multiplicadores distintas, y uno de esos multiplicadores es un 9 que se tipea como 1 lo bastante seguido como para que un validador roto igual pase una prueba superficial: solo difiere cuando un dígito puntual no es cero.

Esta librería los implementa bien, offline, sin ninguna llamada externa.

Qué valida

Función Entrada Qué verifica
validate_cuit CUIT / CUIL 11 dígitos, prefijo conocido, dígito verificador módulo 11
validate_cuil CUIL lo mismo, y rechaza prefijos de persona jurídica
validate_cbu CBU 22 dígitos, dos dígitos verificadores módulo 10 independientes
validate_dni DNI 7–8 dígitos, rango plausible (no existe checksum)
validate_patente Patente formato pre-Mercosur y ambos formatos Mercosur
validate_cpa Código postal 4 dígitos viejo y CPA actual, letra de provincia

Instalación

pip install ar-validators

Requiere Python 3.9 o superior. Nada más.

Uso

Cada validador acepta el número en cualquier forma escrita habitual: los guiones, puntos y espacios se sacan antes de verificar.

from ar_validators import (
    validate_cuit, validate_cuil, validate_cbu,
    validate_dni, validate_patente, validate_cpa,
)

validate_cuit("20000000001").valid        # True
validate_cuit("20 00000000 1").valid      # True

validate_cuil("30000000007").valid        # False — prefijo de empresa
validate_cuil("30000000007").errors
# ["prefix '30' belongs to a legal entity; a CUIL is issued only to natural persons"]

cbu = validate_cbu("0075305826018159083016")
cbu.metadata["bank_code"]                 # "007"
cbu.metadata["branch_code"]               # "5305"

validate_dni("12.345.678").value          # "12345678"

validate_patente("AB123CD").metadata      # format "mercosur", vehicle_type "auto"
validate_patente("A123BC").metadata       # format "mercosur", vehicle_type "moto"
validate_patente("ABC123").metadata       # format "pre_mercosur", vehicle_type None

validate_cpa("C1043AAZ").metadata["province"]   # "Ciudad Autónoma de Buenos Aires"
validate_cpa("1043").metadata["format"]         # "legacy"

Formateo

from ar_validators import format_cuit, format_cbu, format_dni

format_cuit("20000000001")    # "20-00000000-1"
format_cbu("0075305826018159083016")
                              # "00753058 26018159083016"
format_dni("12345678")        # "12.345.678"

Los formateadores devuelven None cuando la entrada no tiene la cantidad de dígitos correcta. No verifican el checksum: si eso importa, validá primero.

Tipo de contribuyente

from ar_validators import cuit_type

cuit_type("20000000001")   # "persona_fisica_masculino"
cuit_type("27000000006")   # "persona_fisica_femenino"
cuit_type("30000000007")   # "persona_juridica"

Resultado de la validación

Cada validador devuelve un ValidationResult inmutable:

Campo Tipo Significado
valid bool True cuando pasó todas las verificaciones
value str La entrada normalizada: solo dígitos, o mayúsculas canónicas para patentes y códigos postales
errors list[str] Por qué falló. Vacío cuando es válido
metadata dict Información derivada de una entrada válida. Vacío cuando es inválida

El resultado es truthy cuando es válido, así que se lee natural en un condicional:

if validate_cuit(user_input):
    ...

Generación de datos de prueba

Poner un CUIT real en un fixture de test es poner la clave fiscal de una persona real en tu repositorio. Usá los generadores: producen números con dígito verificador correcto que no son de nadie.

from ar_validators import generate_cuit, generate_cbu

generate_cuit()                  # prefijo al azar
generate_cuit(prefix="27")       # prefijo específico
generate_cbu(bank_code="007")    # banco específico

import random
generate_cuit(rng=random.Random(42))   # reproducible

Notas

Todos los números que aparecen en este README son sintéticos. Los CUIT usan base cero, que nunca se emite, y el CBU salió de generate_cbu. Ninguno pertenece a una persona ni a una cuenta real.

Esta librería valida formato y checksum, nada más. No verifica si un número está registrado en ningún organismo. Un CUIT que pasa acá está bien formado; si alguna vez fue emitido, y a nombre de quién, es una pregunta que solo ARCA puede contestar.

El DNI no tiene dígito verificador, así que validate_dni no puede hacer más que confirmar la forma y un rango plausible.

Licencia

MIT


Built by Carlos Perasso — OrvixLabs

About

Offline validation of Argentine identity numbers: CUIT, CUIL, CBU, DNI, license plates, postal codes. Zero dependencies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages