3162
Comentário:
|
4545
Link para VerificadorDeCpfCnpjSimples
|
Deleções são marcadas assim. | Adições são marcadas assim. |
Linha 1: | Linha 1: |
#pragma section-numbers off | |
Linha 4: | Linha 3: |
Esse módulo contém algumas funções e classes úteis para aplicações que envolvam cadastros e necessitem validar números de CPF antes de incluir no banco de dados. Além de útil, também é um bom exemplo de como otimizar código que lida com manipulação de números e strings, usando as funções reduce(), map() e ''list compreensions''. | Esse módulo contém algumas funções e classes úteis para aplicações que envolvam cadastros e necessitem validar números de CPF antes de incluir no banco de dados. Ver também: VerificadorDeCpfCnpjSimples. |
Linha 7: | Linha 8: |
Linha 14: | Linha 16: |
def _gen(cpf): """Gera o próximo dígito do número de CPF |
""" |
Linha 17: | Linha 18: |
""" res = [] for i in range(len(cpf)): a = cpf[i] b = (len(cpf) + 1 - i) res.append(b * a) res = reduce(int.__add__, res) % 11 if res > 1: return (11 - res) else: return 0 |
Este módulo fornece uma classe wrapper para ser usada com números de CPF, que além de oferecer um método simples de verificação, também conta com métodos para comparação e conversão. |
Linha 32: | Linha 23: |
def _translate(cpf): """Traduz o número como string na forma: |
>>> a = CPF('56068332551') >>> b = CPF('560.683.325-51') >>> c = CPF((1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0)) >>> assert a.valido() >>> assert b.valido() >>> assert not c.valido() >>> assert a == b >>> assert not b == c >>> assert not a == c >>> assert eval(repr(a)) == a >>> assert eval(repr(b)) == b >>> assert eval(repr(c)) == c >>> assert str(a) == \"560.683.325-51\" >>> assert str(b) == str(a) >>> assert str(c) == \"123.456.789-00\" |
Linha 35: | Linha 39: |
123.456.789-10 | """ |
Linha 37: | Linha 41: |
para a forma: 12345678910 """ i = xrange(256) t = [' '] * 256 e = ''.join([chr(x) for x in i if not chr(x).isdigit()]) for x in i: if chr(x).isdigit(): t[x] = chr(x) return cpf.translate(''.join(t), e) |
|
Linha 57: | Linha 46: |
_gen = staticmethod(_gen) _translate = staticmethod(_translate) |
|
Linha 61: | Linha 47: |
"""O argumento cpf pode ser uma string nas formas: | """Classe representando um número de CPF |
Linha 63: | Linha 49: |
12345678910 123.456.789-10 ou uma lista ou tuple [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0] (1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0) |
>>> a = CPF('95524361503') >>> b = CPF('955.243.615-03') >>> c = CPF([9, 5, 5, 2, 4, 3, 6, 1, 5, 0, 3]) |
Linha 71: | Linha 54: |
try: basestring except: basestring = (str, unicode) |
|
Linha 73: | Linha 61: |
cpf = cpf.replace(".", "") cpf = cpf.replace("-", "") |
|
Linha 74: | Linha 64: |
cpf = self._translate(cpf) | raise ValueError("Valor não segue a forma xxx.xxx.xxx-xx") |
Linha 76: | Linha 66: |
self.cpf = [int(x) for x in cpf] | if len(cpf) < 11: raise ValueError("O número de CPF deve ter 11 digítos") self.cpf = map(int, cpf) |
Linha 81: | Linha 75: |
>>> a = CPF('95524361503') >>> a[9] == '0' True >>> a[10] == '3' True >>> a[9] == 0 False >>> a[10] == 3 False |
|
Linha 82: | Linha 86: |
return self.cpf[index] | return str(self.cpf[index]) |
Linha 89: | Linha 92: |
>>> a = CPF('95524361503') >>> print repr(a) CPF('95524361503') >>> eval(repr(a)) == a True |
|
Linha 91: | Linha 100: |
Linha 97: | Linha 105: |
>>> a = CPF('95524361503') >>> b = CPF('955.243.615-03') >>> c = CPF('123.456.789-00') >>> a == b True >>> a != c True >>> b != c True |
|
Linha 98: | Linha 116: |
Linha 104: | Linha 121: |
"""Retorna uma representação do CPF na forma: | """Retorna uma string do CPF na forma com pontos e traço |
Linha 106: | Linha 123: |
123.456.789-10 | >>> a = CPF('95524361503') >>> str(a) '955.243.615-03' |
Linha 109: | Linha 129: |
d = iter("..-") |
d = ((3, "."), (7, "."), (11, "-")) |
Linha 112: | Linha 131: |
for i in xrange(3, 12, 4): s.insert(i, d.next()) |
for i, v in d: s.insert(i, v) |
Linha 117: | Linha 136: |
def isValid(self): | def valido(self): |
Linha 120: | Linha 139: |
>>> a = CPF('95524361503') >>> a.valido() True >>> b = CPF('12345678900') >>> b.valido() False |
|
Linha 121: | Linha 147: |
cpf = self.cpf[:9] # pegamos apenas os 9 primeiros dígitos do cpf e geramos os # dois dígitos que faltam while len(cpf) < 11: r = sum(map(lambda(i,v):(len(cpf)+1-i)*v,enumerate(cpf))) % 11 if r > 1: f = 11 - r else: f = 0 cpf.append(f) # se o número com os digítos faltantes coincidir com o número # original, então ele é válido return bool(cpf == self.cpf) def __nonzero__(self): """Valida o número de cpf |
|
Linha 122: | Linha 167: |
s = self.cpf[:9] s.append(self._gen(s)) s.append(self._gen(s)) return s == self.cpf[:] |
>>> a = CPF('95524361503') >>> bool(a) True >>> b = CPF('12345678900') >>> bool(b) False >>> if a: ... print 'OK' ... OK |
Linha 127: | Linha 178: |
}}} | >>> if b: ... print 'OK' ... >>> """ return self.valido() |
Linha 131: | Linha 188: |
== Exemplo de uso == | if __name__ == "__main__": |
Linha 133: | Linha 190: |
{{{ #!python #/usr/bin/env python # -*- coding:UTF-8 -*- from cpf import CPF # Estes números foram gerados aleatoriamente :) VALIDO = "113.451.253-80" INVALIDO = "31354110274" # qualquer um dos dois formatos (com pontos ou não) pode ser usado valido = CPF(VALIDO) invalido = CPF(INVALIDO) assert valido.verificar() assert not invalido.verificar() |
import doctest, sys doctest.testmod(sys.modules[__name__]) |
Linha 161: | Linha 199: |
Pedro Werneck | PedroWerneck |
Receita: Verificador de CPF
Esse módulo contém algumas funções e classes úteis para aplicações que envolvam cadastros e necessitem validar números de CPF antes de incluir no banco de dados.
Ver também: VerificadorDeCpfCnpjSimples.
Código
1 #/usr/bin/env python
2 # -*- coding:UTF-8 -*-
3
4
5 """
6
7 Este módulo fornece uma classe wrapper para ser usada com números de
8 CPF, que além de oferecer um método simples de verificação, também
9 conta com métodos para comparação e conversão.
10
11
12 >>> a = CPF('56068332551')
13 >>> b = CPF('560.683.325-51')
14 >>> c = CPF((1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0))
15 >>> assert a.valido()
16 >>> assert b.valido()
17 >>> assert not c.valido()
18 >>> assert a == b
19 >>> assert not b == c
20 >>> assert not a == c
21 >>> assert eval(repr(a)) == a
22 >>> assert eval(repr(b)) == b
23 >>> assert eval(repr(c)) == c
24 >>> assert str(a) == \"560.683.325-51\"
25 >>> assert str(b) == str(a)
26 >>> assert str(c) == \"123.456.789-00\"
27
28 """
29
30
31
32
33 class CPF(object):
34
35 def __init__(self, cpf):
36 """Classe representando um número de CPF
37
38 >>> a = CPF('95524361503')
39 >>> b = CPF('955.243.615-03')
40 >>> c = CPF([9, 5, 5, 2, 4, 3, 6, 1, 5, 0, 3])
41
42 """
43
44 try:
45 basestring
46 except:
47 basestring = (str, unicode)
48
49 if isinstance(cpf, basestring):
50 cpf = cpf.replace(".", "")
51 cpf = cpf.replace("-", "")
52 if not cpf.isdigit():
53 raise ValueError("Valor não segue a forma xxx.xxx.xxx-xx")
54
55 if len(cpf) < 11:
56 raise ValueError("O número de CPF deve ter 11 digítos")
57
58 self.cpf = map(int, cpf)
59
60
61 def __getitem__(self, index):
62 """Retorna o dígito em index como string
63
64 >>> a = CPF('95524361503')
65 >>> a[9] == '0'
66 True
67 >>> a[10] == '3'
68 True
69 >>> a[9] == 0
70 False
71 >>> a[10] == 3
72 False
73
74 """
75 return str(self.cpf[index])
76
77 def __repr__(self):
78 """Retorna uma representação 'real', ou seja:
79
80 eval(repr(cpf)) == cpf
81
82 >>> a = CPF('95524361503')
83 >>> print repr(a)
84 CPF('95524361503')
85 >>> eval(repr(a)) == a
86 True
87
88 """
89 return "CPF('%s')" % ''.join([str(x) for x in self.cpf])
90
91 def __eq__(self, other):
92 """Provê teste de igualdade para números de CPF
93
94 >>> a = CPF('95524361503')
95 >>> b = CPF('955.243.615-03')
96 >>> c = CPF('123.456.789-00')
97 >>> a == b
98 True
99 >>> a != c
100 True
101 >>> b != c
102 True
103
104 """
105 if isinstance(other, CPF):
106 return self.cpf == other.cpf
107 return False
108
109 def __str__(self):
110 """Retorna uma string do CPF na forma com pontos e traço
111
112 >>> a = CPF('95524361503')
113 >>> str(a)
114 '955.243.615-03'
115
116
117 """
118 d = ((3, "."), (7, "."), (11, "-"))
119 s = map(str, self.cpf)
120 for i, v in d:
121 s.insert(i, v)
122 r = ''.join(s)
123 return r
124
125 def valido(self):
126 """Valida o número de cpf
127
128 >>> a = CPF('95524361503')
129 >>> a.valido()
130 True
131 >>> b = CPF('12345678900')
132 >>> b.valido()
133 False
134
135 """
136 cpf = self.cpf[:9]
137 # pegamos apenas os 9 primeiros dígitos do cpf e geramos os
138 # dois dígitos que faltam
139 while len(cpf) < 11:
140
141 r = sum(map(lambda(i,v):(len(cpf)+1-i)*v,enumerate(cpf))) % 11
142
143 if r > 1:
144 f = 11 - r
145 else:
146 f = 0
147 cpf.append(f)
148
149 # se o número com os digítos faltantes coincidir com o número
150 # original, então ele é válido
151 return bool(cpf == self.cpf)
152
153 def __nonzero__(self):
154 """Valida o número de cpf
155
156 >>> a = CPF('95524361503')
157 >>> bool(a)
158 True
159 >>> b = CPF('12345678900')
160 >>> bool(b)
161 False
162 >>> if a:
163 ... print 'OK'
164 ...
165 OK
166
167 >>> if b:
168 ... print 'OK'
169 ...
170 >>>
171 """
172
173 return self.valido()
174
175
176
177 if __name__ == "__main__":
178
179 import doctest, sys
180 doctest.testmod(sys.modules[__name__])
Volta para CookBook.