import re
from abrasileirado.enums import TipoLivroRcpnEnum, UnidadeFederativaStrEnum
[docs]
class CodigoValidavel:
"""Classe base para códigos brasileiros validáveis.
A classe centraliza normalização de dígitos, representação mascarada, igualdade por valor e validação básica.
Subclasses devem definir o tamanho total esperado e, quando necessário, implementar máscara e regras específicas
da autoridade responsável pelo padrão.
Examples:
.. code-block:: python
class CodigoSempreValido(CodigoValidavel):
def _is_valid(self, code: str) -> bool:
return True
codigo = CodigoSempreValido("1")
print(codigo) # Saída: 1
print(codigo.digitos) # Saída: 1
"""
def __init__(self, code: str):
if not self._is_valid(code):
classname = self.__class__.__name__
raise ValueError(f"{classname} inválido.")
self.__clean_code: str = self._normalize(code).zfill(self._full_digits)
self.__masked_code: str = self._mask_code(code)
@property
def _full_digits(self) -> int:
return 1
@property
def digitos(self) -> str:
"""Retorna apenas os dígitos do código, sem máscara."""
return self.__clean_code
def __str__(self) -> str:
"""Retorna o código formatado com máscara, se aplicável."""
return self.__masked_code
def __eq__(self, other: object) -> bool:
if other.__class__ is not self.__class__:
return NotImplemented
return self.digitos == other.digitos
def __hash__(self) -> int:
return hash((self.__class__, self.digitos))
[docs]
@classmethod
def is_valid(cls, code: str) -> bool:
try:
cls(code)
except ValueError:
return False
return True
def _normalize(self, code: str) -> str:
"""Retorna apenas os dígitos do código, sem máscara."""
return "".join(c for c in filter(str.isdigit, code))
def _mask_code(self, code: str) -> str:
"""Retorna o código formatado com máscara, se aplicável. Subclasses devem implementar esse método para aplicar
a máscara específica do código.
Arguments:
code (str): O código a ser formatado com máscara.
Returns:
str: O código formatado com máscara.
"""
return self._normalize(code).zfill(self._full_digits)
def _basic_digits_validation(self, code: str) -> str | None:
"""Realiza validações básicas comuns a códigos numéricos, como quantidade de dígitos, não aceitar todos os
dígitos iguais, etc. Subclasses podem usar esse método para realizar validações básicas antes de implementar
validações específicasadicionais, como dígitos verificadores, formato, etc.
Arguments:
code (str): O código a ser validado.
Returns:
str: O código limpo contendo apenas os dígitos, se as validações básicas forem aprovadas.
bool: False se as validações básicas falharem.
"""
if code is None:
return None
value = self._normalize(code)
# Não informou ou informou uma string vazia
if value is None or value.strip() == "":
return None
# Com menos de 3 dígitos não é válido, mesmo que os dígitos verificadores sejam tecnicamente corretos
if len(value.strip()) < 3 or len(value.strip()) > self._full_digits:
return None
# Não aceita todos os dígitos iguais
if value == (value[0] * self._full_digits):
return None
return value
def _is_valid(self, code: str) -> bool:
"""Verifica se o código é válido, realizando validações básicas como quantidade de dígitos, não aceitar todos
os dígitos iguais, etc.
Subclasses devem implementar validações específicas adicionais, como dígitos verificadores, formato, etc.
Arguments:
code (str): O código a ser validado.
Returns:
bool: True se o código for válido, False caso contrário.
"""
return len(self._basic_digits_validation(code) or "") == self._full_digits
[docs]
class CEP(CodigoValidavel):
"""Classe imutável para representar um CEP (Código de Endereçamento Postal).
O CEP é um código numérico de 8 dígitos usado para identificar áreas de entrega no Brasil.
O padrão é definido e utilizado pela Empresa Brasileira de Correios e Telégrafos (ECT).
A classe aceita o valor com ou sem máscara e normaliza a saída no formato 99999-999.
Examples:
.. code-block:: python
cep1 = CEP("59015300")
print(cep1) # Saída: 59015-300
print(cep1.digitos) # Saída: 59015300
cep2 = CEP("59015-300")
print(cep2) # Saída: 59015-300
"""
@property
def _full_digits(self) -> int:
return 8
MASK = "99999-999"
REGEX = r"^\d{5}-\d{3}$"
def _mask_code(self, code: str) -> str:
digits = self._normalize(code)
return f"{digits[:5]}-{digits[5:]}"
[docs]
class EnderecoBrasil:
"""Classe imutável para representar um endereço postal brasileiro.
O endereço reúne logradouro, número, bairro, município, UF, CEP e complemento opcional.
A saída segue formatos postais usados pela Empresa Brasileira de Correios e Telégrafos (ECT).
Examples:
.. code-block:: python
endereco = EnderecoBrasil(
logradouro="Rua das Flores",
numero="123",
bairro="Jardim Primavera",
municipio="São Paulo",
uf=UnidadeFederativaStrEnum.SP,
cep=CEP("12345678"),
complemento="Apto 45"
)
print(endereco) # Saída: Rua das Flores 123, Apto 45\nJardim Primavera\n12345-678 São Paulo/SP
print(endereco.ect_extendido) # Saída: Rua das Flores 123, Apto 45\nJardim Primavera\nSão Paulo/SP\n12345-678
"""
def __init__(
self,
logradouro: str,
numero: str,
bairro: str,
municipio: str,
uf: UnidadeFederativaStrEnum,
cep: CEP,
complemento: str | None = None,
):
self.__logradouro = logradouro
self.__numero = numero
self.__bairro = bairro
self.__municipio = municipio
self.__uf = uf
self.__cep = cep
self.__complemento = complemento
@property
def linha_logradouro(self) -> str:
_complemento = f", {self.__complemento}" if self.__complemento else ""
return f"{self.__logradouro} {self.__numero}{_complemento}"
@property
def logradouro(self) -> str:
return self.__logradouro
@property
def numero(self) -> str:
return self.__numero
@property
def bairro(self) -> str:
return self.__bairro
@property
def municipio(self) -> str:
return self.__municipio
@property
def uf(self) -> UnidadeFederativaStrEnum:
return self.__uf
@property
def cep(self) -> CEP:
return self.__cep
@property
def complemento(self) -> str | None:
return self.__complemento
@property
def ect_extendido(self) -> str:
"""Retorna o endereço completo extendido da ECT."""
return f"{self.linha_logradouro}\n{self.__bairro}\n{self.__municipio}/{self.__uf.value}\n{self.__cep}"
@property
def ect_padrao(self) -> str:
"""Retorna o endereço formatado no formato padrão da ECT."""
return f"{self.linha_logradouro}\n{self.__bairro}\n{self.__cep} {self.__municipio}/{self.__uf.value}"
def __str__(self) -> str:
return self.ect_padrao
def __eq__(self, other: object) -> bool:
if other.__class__ is not self.__class__:
return NotImplemented
return (
self.logradouro,
self.numero,
self.bairro,
self.municipio,
self.uf,
self.cep,
self.complemento,
) == (
other.logradouro,
other.numero,
other.bairro,
other.municipio,
other.uf,
other.cep,
other.complemento,
)
def __hash__(self) -> int:
return hash(
(
self.__class__,
self.logradouro,
self.numero,
self.bairro,
self.municipio,
self.uf,
self.cep,
self.complemento,
)
)
[docs]
class CPF(CodigoValidavel):
"""Classe imutável para representar um CPF (Cadastro de Pessoas Físicas).
O CPF é um número de identificação fiscal utilizado no Brasil para pessoas físicas.
Ele é composto por 11 dígitos, onde os 9 primeiros são a base do número e os 2 últimos são dígitos verificadores
calculados a partir dos 9 primeiros.
O padrão é definido pela Receita Federal do Brasil (RFB).
Essa classe valida o CPF no momento da criação, garantindo que apenas CPFs válidos possam ser instanciados.
O CPF pode ser representado tanto no formato apenas com dígitos (ex: 12345678901) quanto no formato com máscara
(ex: 123.456.789-01).
Examples:
.. code-block:: python
cpf1 = CPF("12345678901")
print(cpf1) # Saída: 123.456.789-01 (CPF completo, DV corretos, sem máscara)
print(cpf1.digitos) # Saída: 12345678901
# Verificando validade
print(CPF.is_valid("12345678901")) # Saída: True
print(CPF.is_valid("123.456.789-01")) # Saída: True
print(CPF.is_valid("1234567890")) # Saída: False (menos de 11 dígitos)
print(CPF.is_valid("123456789012")) # Saída: False (mais de 11 dígitos)
print(CPF.is_valid("00000000000")) # Saída: False (todos os dígitos iguais)
# Clonando um CPF
cpf2 = CPF(str(cpf1))
"""
MASK = "99.999.999/9999-00"
REGEX = re.compile(r"^(\d{2})[.-]?(\d{3})[.-]?(\d{3})/(\d{4})-(\d{2})$")
@property
def _full_digits(self) -> int:
return 11
def _mask_code(self, code: str) -> str:
digits = self._normalize(code).zfill(self._full_digits)
return f"{digits[:3]}.{digits[3:6]}.{digits[6:9]}-{digits[9:]}"
def _is_valid(self, code: str) -> bool:
value = self._basic_digits_validation(code)
if not value:
return False
v = value.zfill(self._full_digits)
dv1 = sum([int(v[i]) * (10 - i) for i in range(0, 9)]) * 10 % 11
dv2 = sum([int(v[i]) * (11 - i) for i in range(0, 10)]) * 10 % 11
dv1 = dv1 if dv1 != 10 else 0
dv2 = dv2 if dv2 != 10 else 0
return value[-2:] == f"{dv1}{dv2}"
[docs]
class CNPJ(CodigoValidavel):
"""Classe imutável para representar um CNPJ (Cadastro Nacional de Pessoa Jurídica).
O CNPJ é um número de identificação fiscal utilizado no Brasil para pessoas jurídicas.
Ele é composto por 14 dígitos, onde os 12 primeiros são a base do número e os 2 últimos são dígitos verificadores
calculados a partir dos 12 primeiros.
O padrão é definido pela Receita Federal do Brasil (RFB).
Essa classe valida o CNPJ no momento da criação, garantindo que apenas CNPJs válidos possam ser instanciados.
O CNPJ pode ser representado tanto no formato apenas com dígitos (ex: 12345678900005) quanto no formato com máscara
(ex: 12.345.678/9000-05).
Examples:
.. code-block:: python
cnpj = CNPJ("12345678900005")
print(cnpj) # Saída: 12.345.678/9000-05
print(cnpj.digitos) # Saída: 12345678900005
cnpj2 = CNPJ("12.345.678/9000-05")
print(cnpj2) # Saída: 12.345.678/9000-05
"""
MASK = "AA.AAA.AAA/AAAA-00"
REGEX = re.compile(
r"^([A-Z0-9]{2})[.]?([A-Z0-9]{3})[.]?([A-Z0-9]{3})/([A-Z0-9]{4})-?(\d{2})$",
re.IGNORECASE,
)
@property
def _full_digits(self) -> int:
return 14
def _normalize(self, code: str) -> str:
return "".join(c for c in (code or "").upper() if c.isalnum())
def _mask_code(self, code: str) -> str:
value = self._normalize(code).zfill(self._full_digits)
return f"{value[:2]}.{value[2:5]}.{value[5:8]}/{value[8:12]}-{value[12:]}"
def _basic_cnpj_validation(self, code: str) -> str | None:
value = self._normalize(code)
if not value:
return None
if len(value) != self._full_digits:
return None
dv = value[12:]
if not dv.isdigit():
return None
# Mantém a proteção contra sequências repetidas no caso puramente numérico.
if value.isdigit() and value == value[0] * self._full_digits:
return None
return value
@staticmethod
def _char_value(char: str) -> int:
return ord(char) - 48
@classmethod
def _calculate_dvs(cls, base: str) -> str:
weights1 = (5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2)
weights2 = (6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2)
values = [cls._char_value(c) for c in base]
total1 = sum(v * w for v, w in zip(values, weights1))
rest1 = total1 % 11
dv1 = 0 if rest1 in (0, 1) else 11 - rest1
values2 = values + [dv1]
total2 = sum(v * w for v, w in zip(values2, weights2))
rest2 = total2 % 11
dv2 = 0 if rest2 in (0, 1) else 11 - rest2
return f"{dv1}{dv2}"
def _is_valid(self, code: str) -> bool:
value = self._basic_cnpj_validation(code)
if not value:
return False
base = value[:12]
dv_informado = value[12:]
dv_calculado = self._calculate_dvs(base)
return dv_informado == dv_calculado
[docs]
class CNES(CodigoValidavel):
"""Classe imutável para representar um CNES (Cadastro Nacional de Estabelecimento de Saúde).
O CNES é um número de identificação utilizado para estabelecimentos de saúde no Brasil.
O cadastro é mantido pelo Ministério da Saúde/DATASUS.
A classe representa o código numérico de 7 dígitos sem máscara.
Examples:
.. code-block:: python
cnes = CNES("2079305")
print(cnes) # Saída: 2079305
print(cnes.digitos) # Saída: 2079305
"""
MASK = "9999999"
REGEX = re.compile(r"^(\d{7})$")
@property
def _full_digits(self) -> int:
return 7
[docs]
class CNS(CodigoValidavel):
"""Classe imutável para representar um CNS (Cartão Nacional de Saúde).
O CNS é um número de identificação utilizado para cidadãos brasileiros no sistema de saúde, composto por 15 dígitos,
onde os 11 primeiros são a base do número e os 4 últimos são dígitos verificadores calculados a partir dos 11
primeiros.
O padrão é utilizado pelo Sistema Único de Saúde (SUS), sob gestão do Ministério da Saúde/DATASUS.
A classe representa o código numérico sem máscara.
Examples:
.. code-block:: python
cns = CNS("898001160444648")
print(cns) # Saída: 898001160444648
print(cns.digitos) # Saída: 898001160444648
"""
MASK = "999 9999 9999 9999"
REGEX = re.compile(r"^(\d{3}) (\d{4}) (\d{4}) (\d{4})$")
@property
def _full_digits(self) -> int:
return 15
def _is_valid(self, code: str) -> bool:
digits = self._basic_digits_validation(code)
if not digits or len(digits) != self._full_digits:
return False
if digits[0] in ("1", "2"):
base = digits[:11]
total = sum(int(digit) * weight for digit, weight in zip(base, range(15, 4, -1)))
dv = 11 - (total % 11)
dv = 0 if dv == 11 else dv
if dv == 10:
total += 2
dv = 11 - (total % 11)
expected = f"{base}001{dv}"
else:
expected = f"{base}000{dv}"
return digits == expected
if digits[0] in ("7", "8", "9"):
total = sum(int(digit) * weight for digit, weight in zip(digits, range(15, 0, -1)))
return total % 11 == 0
return False
[docs]
class NUP(CodigoValidavel):
"""Classe imutável para representar um NUP (Número Único de Processo).
O NUP é um número de identificação utilizado para processos judiciais e administrativos no Brasil.
O padrão é usado pelo Conselho Nacional de Justiça (CNJ) e pela Administração Pública para protocolo e tramitação.
Ele é composto por 17 dígitos:
- 5 para a unidade protocolizadora,
- 6 para o sequencial anual,
- 4 para o ano,
- 2 para o dígito verificador.
Examples:
.. code-block:: python
nup = NUP("23520005177202676")
print(nup) # Saída: 23520.005177/2026-76
print(nup.digitos) # Saída: 23520005177202676
nup2 = NUP("23520.005177/2026-76")
print(nup2) # Saída: 23520.005177/2026-76
"""
MASK = "99999.999999/9999-99"
REGEX = re.compile(r"^(\d{5})\.?(\d{6})/(\d{4})-(\d{2})$")
@property
def _full_digits(self) -> int:
return 17
def _mask_code(self, code: str) -> str:
digits = self._normalize(code).zfill(self._full_digits)
return f"{digits[:5]}.{digits[5:11]}/{digits[11:15]}-{digits[15:]}"
def _is_valid(self, code: str) -> bool:
digits = self._normalize(code)
if len(digits) != 17:
return False
base = digits[:15]
given_dv = digits[15:]
def calc_dv(number: str, start_weight: int = 2) -> int:
total = 0
weight = start_weight
for ch in reversed(number):
total += int(ch) * weight
weight += 1
dv = 11 - (total % 11)
return dv % 10
dv1 = calc_dv(base, 2)
dv2 = calc_dv(base + str(dv1), 2)
return given_dv == f"{dv1}{dv2}"
[docs]
class PIS(CodigoValidavel):
"""Classe imutável para representar um PIS (Programa de Integração Social).
O PIS é um número de identificação utilizado para trabalhadores no Brasil.
O cadastro é associado a políticas trabalhistas e sociais do Governo Federal.
A classe representa o código de 11 dígitos e normaliza a saída em grupos.
Examples:
.. code-block:: python
pis = PIS("12044568103")
print(pis) # Saída: 120 445 681 03
print(pis.digitos) # Saída: 12044568103
"""
MASK = "999.99999.99-9"
REGEX = re.compile(r"^(\d{3})\.(\d{5})\.(\d{2})-(\d{1})$")
@property
def _full_digits(self) -> int:
return 11
def _mask_code(self, code: str) -> str:
digits = self._normalize(code).zfill(self._full_digits)
return f"{digits[:3]} {digits[3:6]} {digits[6:9]} {digits[9:]}"
def _is_valid(self, code: str) -> bool:
digits = self._basic_digits_validation(code)
if not digits or len(digits) != self._full_digits:
return False
weights = (3, 2, 9, 8, 7, 6, 5, 4, 3, 2)
dv = 11 - (sum(int(digit) * weight for digit, weight in zip(digits[:10], weights)) % 11)
dv = 0 if dv in (10, 11) else dv
return digits[-1] == str(dv)
[docs]
class RENAVAM(CodigoValidavel):
"""Classe imutável para representar um RENAVAM.
O RENAVAM é o Registro Nacional de Veículos Automotores, usado para identificar veículos no Brasil.
O padrão é mantido pela Secretaria Nacional de Trânsito (Senatran).
A classe representa o código numérico de 11 dígitos e valida seu dígito verificador.
Examples:
.. code-block:: python
renavam = RENAVAM("63988496249")
print(renavam) # Saída: 63988496249
print(renavam.digitos) # Saída: 63988496249
"""
MASK = "99999999999"
REGEX = re.compile(r"^\d{11}$")
@property
def _full_digits(self) -> int:
return 11
def _mask_code(self, code: str) -> str:
digits = self._normalize(code).zfill(self._full_digits)
return digits
def _is_valid(self, code: str) -> bool:
digits = self._basic_digits_validation(code)
if not digits or len(digits) != self._full_digits or not self.REGEX.fullmatch(digits):
return False
weights = (3, 2, 9, 8, 7, 6, 5, 4, 3, 2)
dv = 11 - (sum(int(digit) * weight for digit, weight in zip(digits[:10], weights)) % 11)
dv = 0 if dv >= 10 else dv
return digits[-1] == str(dv)
[docs]
class TituloEleitoral(CodigoValidavel):
"""Classe imutável para representar um Título Eleitoral.
O Título Eleitoral identifica pessoas aptas ao cadastro eleitoral brasileiro.
O padrão é definido pela Justiça Eleitoral, sob responsabilidade do Tribunal Superior Eleitoral (TSE).
A classe representa o código numérico de 12 dígitos e valida seus dígitos verificadores.
Examples:
.. code-block:: python
titulo = TituloEleitoral("123456780191")
print(titulo) # Saída: 123456780191
print(titulo.digitos) # Saída: 123456780191
"""
MASK = "999999999999"
REGEX = re.compile(r"^\d{12}$")
@property
def _full_digits(self) -> int:
return 12
def _mask_code(self, code: str) -> str:
digits = self._normalize(code).zfill(self._full_digits)
return digits
def _is_valid(self, code: str) -> bool:
digits = self._basic_digits_validation(code)
if not digits or len(digits) != self._full_digits or not self.REGEX.fullmatch(digits):
return False
if digits[8:10] not in {f"{uf:02d}" for uf in range(1, 12)} | {"99"}:
return False
dv1 = sum(int(digit) * weight for digit, weight in zip(digits[:8], range(2, 10))) % 11
dv1 = 0 if dv1 == 10 else dv1
dv2 = sum(int(digit) * weight for digit, weight in zip(digits[8:10] + str(dv1), range(7, 10))) % 11
dv2 = 0 if dv2 == 10 else dv2
return digits[-2:] == f"{dv1}{dv2}"
[docs]
class CertidaoRCPN(CodigoValidavel):
"""Classe imutável para representar uma certidão RCPN.
A matrícula RCPN identifica certidões do Registro Civil das Pessoas Naturais.
O padrão é regulado pelo Conselho Nacional de Justiça (CNJ) e usa 32 dígitos, incluindo códigos de serventia,
acervo, tipo de livro, livro, folha, termo e dígitos verificadores.
Examples:
.. code-block:: python
certidao = CertidaoRCPN("12345601552024100001001000000167")
print(certidao) # Saída: 123456.01.55.2024.1.00001.001.0000001-67
print(certidao.digitos) # Saída: 12345601552024100001001000000167
print(certidao.tipo_livro.description) # Saída: Nascimento
"""
MASK = "999999.99.99.9999.9.99999.999.9999999-00"
REGEX = rcpn_pattern = re.compile(
r"^\d{6}" # Código Nacional da Serventia (6 dígitos)
r"(0[1-9]|[1-9]\d)" # Código do acervo (07-08: 01-99)
r"55" # Código fixo RCPN (09-10)
r"\d{4}" # Ano (11-14: ex. 2009-2026)
r"[1-7]" # Tipo de livro (15: 1 a 7)
r"\d{5}" # Número do livro (16-20: 00000-99999)
r"\d{3}" # Folha (21-23: 001-999)
r"\d{7}" # Termo (24-30: 0000001-9999999)
r"\d{2}$" # Dígitos verificadores (31-32)
)
@property
def _full_digits(self) -> int:
return 32
def _mask_code(self, code: str) -> str:
digits = self._normalize(code).zfill(self._full_digits)
return (
f"{digits[:6]}.{digits[6:8]}.{digits[8:10]}.{digits[10:14]}.{digits[14]}."
f"{digits[15:20]}.{digits[20:23]}.{digits[23:30]}-{digits[30:]}"
)
def _is_valid(self, code: str) -> bool:
if code is None:
return False
digits = self._normalize(code)
if len(digits) != self._full_digits:
return False
return bool(self.REGEX.fullmatch(digits)) and int(digits) % 97 == 1
@property
def codigo_serventia(self) -> str:
"""1º ao 6º: Código da Serventia (Cartório)."""
return self.digitos[:6]
@property
def codigo_acervo(self) -> str:
"""7º e 8º: Código do Acervo."""
return self.digitos[6:8]
@property
def registro_civil(self) -> str:
"""9º e 10º: Registro Civil."""
return self.digitos[8:10]
@property
def ano_registro(self) -> str:
"""11º ao 14º: Ano do registro."""
return self.digitos[10:14]
@property
def tipo_livro(self) -> TipoLivroRcpnEnum:
"""15º: Tipo de Livro."""
codigo = int(self.digitos[14])
return next(tipo_livro for tipo_livro in TipoLivroRcpnEnum if tipo_livro.value == codigo)
@property
def numero_livro(self) -> str:
"""16º ao 20º: Número do Livro."""
return self.digitos[15:20]
@property
def numero_folha(self) -> str:
"""21º ao 23º: Número da Folha."""
return self.digitos[20:23]
@property
def numero_termo(self) -> str:
"""24º ao 30º: Número do Termo."""
return self.digitos[23:30]
@property
def dv(self) -> str:
"""31º e 32º: Dígitos Verificadores."""
return self.digitos[30:]
[docs]
class Telefone(CodigoValidavel):
"""Classe imutável para representar um telefone brasileiro.
O telefone é representado com DDD de 2 dígitos e número de 9 dígitos.
A numeração telefônica brasileira é regulada pela Agência Nacional de Telecomunicações (Anatel).
A classe normaliza a saída no formato (99) 99999-9999.
Examples:
.. code-block:: python
telefone = Telefone("(84) 98765-4321")
print(telefone) # Saída: (84) 98765-4321
print(telefone.digitos) # Saída: 84987654321
"""
MASK = "(99) 99999-9999"
REGEX = re.compile(r"^\(?[1-9]{2}\)? ?9?\d{4}-?\d{4}$")
@property
def _full_digits(self) -> int:
return 11
def _mask_code(self, code: str) -> str:
digits = self._normalize(code).zfill(self._full_digits)
return f"({digits[:2]}) {digits[2:7]}-{digits[7:]}"
def _is_valid(self, code: str) -> bool:
digits = self._basic_digits_validation(code)
return bool(digits and len(digits) == self._full_digits and self.REGEX.fullmatch(code))
[docs]
class Passaporte(CodigoValidavel):
"""Classe imutável para representar um passaporte brasileiro.
O passaporte é um documento de viagem emitido pela Polícia Federal.
Nesta classe, o código é representado como uma sequência numérica de 8 dígitos.
Examples:
.. code-block:: python
passaporte = Passaporte("12345678")
print(passaporte) # Saída: 12345678
print(passaporte.digitos) # Saída: 12345678
"""
MASK = "99999999"
REGEX = re.compile(r"^\d{8}$")
@property
def _full_digits(self) -> int:
return 8
def _mask_code(self, code: str) -> str:
return self._normalize(code).zfill(self._full_digits)
def _is_valid(self, code: str) -> bool:
digits = self._basic_digits_validation(code)
return bool(digits and len(digits) == self._full_digits and self.REGEX.fullmatch(digits))
[docs]
class PlacaVeicular(CodigoValidavel):
"""Classe imutável para representar uma placa veicular.
A placa veicular identifica veículos automotores no Brasil.
O padrão de emplacamento é definido pelo Conselho Nacional de Trânsito (CONTRAN) e operacionalizado pelo
Sistema Nacional de Trânsito.
Nesta classe, a placa é representada como uma sequência numérica de 7 dígitos.
Examples:
.. code-block:: python
placa = PlacaVeicular("1234567")
print(placa) # Saída: 1234567
print(placa.digitos) # Saída: 1234567
"""
MASK = "9999999"
REGEX = re.compile(r"^\d{7}$")
@property
def _full_digits(self) -> int:
return 7
def _mask_code(self, code: str) -> str:
return self._normalize(code).zfill(self._full_digits)
def _is_valid(self, code: str) -> bool:
digits = self._basic_digits_validation(code)
return bool(digits and len(digits) == self._full_digits and self.REGEX.fullmatch(digits))