-
Notifications
You must be signed in to change notification settings - Fork 53
Expand file tree
/
Copy pathCPF.py
More file actions
134 lines (92 loc) · 3.46 KB
/
CPF.py
File metadata and controls
134 lines (92 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
from random import sample
from validate_docbr.DocumentBase import DocumentBase
class CPF(DocumentBase):
"""Classe referente ao Cadastro de Pessoas Físicas (CPF)."""
def __init__(self, repeated_digits: bool = False) -> None:
self.digits = list(range(10))
self.repeated_digits = repeated_digits
def validate(self, doc: str = '') -> bool:
"""Valida o CPF.
Args:
doc: CPF a ser validado. Aceita com ou sem máscara.
Returns:
True se o CPF for válido, False caso contrário.
"""
if not self._validate_input(doc, ['.', '-']):
return False
digits = list(self._only_digits(doc))
if len(digits) > 11:
return False
if len(digits) < 11:
digits = self._complete_with_zeros(digits)
if not self.repeated_digits and self._check_repeated_digits(digits):
return False
return self._generate_first_digit(digits) == digits[9] \
and self._generate_second_digit(digits) == digits[10]
def generate(self, mask: bool = False) -> str:
"""Gera um CPF válido.
Args:
mask: Se True, retorna o CPF formatado (ex: ``012.345.678-90``).
Returns:
CPF gerado em formato string.
"""
cpf = [str(sample(self.digits, 1)[0]) for _ in range(9)]
cpf.append(self._generate_first_digit(cpf))
cpf.append(self._generate_second_digit(cpf))
cpf = "".join(cpf)
return self.mask(cpf) if mask else cpf
def mask(self, doc: str = '') -> str:
"""Coloca a máscara de CPF no documento.
Args:
doc: CPF com ou sem máscara.
Returns:
CPF formatado no padrão ``XXX.XXX.XXX-XX``.
"""
doc = self._only_digits(doc)
return f"{doc[:3]}.{doc[3:6]}.{doc[6:9]}-{doc[-2:]}"
def _generate_first_digit(self, doc: list) -> str:
"""Gera o primeiro dígito verificador do CPF.
Args:
doc: Lista com os dígitos do CPF.
Returns:
Primeiro dígito verificador.
"""
total = 0
for weight in range(10, 1, -1):
total += int(doc[10 - weight]) * weight
total = (total * 10) % 11
if total == 10:
total = 0
return str(total)
def _generate_second_digit(self, doc: list) -> str:
"""Gera o segundo dígito verificador do CPF.
Args:
doc: Lista com os dígitos do CPF.
Returns:
Segundo dígito verificador.
"""
total = 0
for weight in range(11, 1, -1):
total += int(doc[11 - weight]) * weight
total = (total * 10) % 11
if total == 10:
total = 0
return str(total)
def _check_repeated_digits(self, doc: list[str]) -> bool:
"""Verifica se é um CPF com números repetidos.
Exemplo: ``111.111.111-11``.
Args:
doc: Lista com os dígitos do CPF.
Returns:
True se todos os dígitos forem iguais.
"""
return len(set(doc)) == 1
def _complete_with_zeros(self, doc: list[str]) -> list[str]:
"""Adiciona zeros à esquerda para completar o CPF.
Args:
doc: Lista com os dígitos do CPF incompleto.
Returns:
Lista com 11 dígitos, preenchida com zeros à esquerda.
"""
zeros_needed = 11 - len(doc)
return ['0'] * zeros_needed + doc