cnpj-dv 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cnpj_dv-1.0.0/LICENSE +9 -0
- cnpj_dv-1.0.0/PKG-INFO +313 -0
- cnpj_dv-1.0.0/README.md +282 -0
- cnpj_dv-1.0.0/pyproject.toml +70 -0
- cnpj_dv-1.0.0/setup.cfg +4 -0
- cnpj_dv-1.0.0/src/cnpj_dv/__init__.py +17 -0
- cnpj_dv-1.0.0/src/cnpj_dv/cnpj_check_digits.py +147 -0
- cnpj_dv-1.0.0/src/cnpj_dv/exceptions.py +45 -0
- cnpj_dv-1.0.0/src/cnpj_dv.egg-info/PKG-INFO +313 -0
- cnpj_dv-1.0.0/src/cnpj_dv.egg-info/SOURCES.txt +10 -0
- cnpj_dv-1.0.0/src/cnpj_dv.egg-info/dependency_links.txt +1 -0
- cnpj_dv-1.0.0/src/cnpj_dv.egg-info/top_level.txt +1 -0
cnpj_dv-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Julio L. Muller
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
cnpj_dv-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cnpj-dv
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Utility resources to calculate check digits on CNPJ (Brazilian employer ID)
|
|
5
|
+
Author: Julio L. Muller
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://cnpj-utils.vercel.app/
|
|
8
|
+
Project-URL: Source, https://github.com/LacusSolutions/br-utils-py
|
|
9
|
+
Project-URL: Tracker, https://github.com/LacusSolutions/br-utils-py/issues
|
|
10
|
+
Keywords: cnpj,verificar,verificador,verify,verification,check,check-digit,check-digits,pt-br,br
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Natural Language :: Portuguese (Brazilian)
|
|
15
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX
|
|
18
|
+
Classifier: Operating System :: Unix
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
26
|
+
Classifier: Topic :: Utilities
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/cnpj-dv)
|
|
35
|
+
[](https://pypi.org/project/cnpj-dv)
|
|
36
|
+
[](https://www.python.org/)
|
|
37
|
+
[](https://github.com/LacusSolutions/br-utils-py/actions)
|
|
38
|
+
[](https://github.com/LacusSolutions/br-utils-py)
|
|
39
|
+
[](https://github.com/LacusSolutions/br-utils-py/blob/main/LICENSE)
|
|
40
|
+
|
|
41
|
+
Utility class to calculate check digits on CNPJ (Brazilian employer ID).
|
|
42
|
+
|
|
43
|
+
## Python Support
|
|
44
|
+
|
|
45
|
+
|  |  |  |  |  |
|
|
46
|
+
|--- | --- | --- | --- | --- |
|
|
47
|
+
| Passing ✔ | Passing ✔ | Passing ✔ | Passing ✔ | Passing ✔ |
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
$ pip install cnpj-dv
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Import
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from cnpj_dv import CnpjCheckDigits
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
|
|
63
|
+
### Basic Usage
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
# Calculate check digits from a 12-digit CNPJ base
|
|
67
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
68
|
+
|
|
69
|
+
print(check_digits.first_digit) # returns 9
|
|
70
|
+
print(check_digits.second_digit) # returns 3
|
|
71
|
+
print(check_digits.to_string()) # returns '91415732000793'
|
|
72
|
+
print(check_digits.to_list()) # returns [9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7, 9, 3]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Input Formats
|
|
76
|
+
|
|
77
|
+
The `CnpjCheckDigits` class accepts multiple input formats:
|
|
78
|
+
|
|
79
|
+
#### String Input
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
# Plain string (non-numeric characters are automatically stripped)
|
|
83
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
84
|
+
check_digits = CnpjCheckDigits("91.415.732/0007") # formatting is ignored
|
|
85
|
+
check_digits = CnpjCheckDigits("914157320007") # 12 digits
|
|
86
|
+
check_digits = CnpjCheckDigits("91415732000793") # 14 digits (only first 12 are used)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### List of Strings
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# List of single-character strings
|
|
93
|
+
check_digits = CnpjCheckDigits(["9", "1", "4", "1", "5", "7", "3", "2", "0", "0", "0", "7"])
|
|
94
|
+
|
|
95
|
+
# List with multi-digit strings (automatically flattened)
|
|
96
|
+
check_digits = CnpjCheckDigits(["914157320007"]) # flattens to individual digits
|
|
97
|
+
check_digits = CnpjCheckDigits(["91", "415", "732", "0007"]) # also flattens
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### List of Integers
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
# List of single-digit integers
|
|
104
|
+
check_digits = CnpjCheckDigits([9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7])
|
|
105
|
+
|
|
106
|
+
# List with multi-digit integers (automatically flattened)
|
|
107
|
+
check_digits = CnpjCheckDigits([914157320007]) # flattens to individual digits
|
|
108
|
+
check_digits = CnpjCheckDigits([914, 157, 320, 7]) # also flattens
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Properties
|
|
112
|
+
|
|
113
|
+
#### `first_digit: int`
|
|
114
|
+
|
|
115
|
+
Returns the first check digit (13th digit of the CNPJ).
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
119
|
+
print(check_digits.first_digit) # returns 9
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### `second_digit: int`
|
|
123
|
+
|
|
124
|
+
Returns the second check digit (14th digit of the CNPJ).
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
128
|
+
print(check_digits.second_digit) # returns 3
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Methods
|
|
132
|
+
|
|
133
|
+
#### `to_list() -> list[int]`
|
|
134
|
+
|
|
135
|
+
Returns the complete CNPJ as a list of integers (12 base digits + 2 check digits).
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
139
|
+
print(check_digits.to_list()) # returns [9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7, 9, 3]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### `to_string() -> str`
|
|
143
|
+
|
|
144
|
+
Returns the complete CNPJ as a string (12 base digits + 2 check digits).
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
148
|
+
print(check_digits.to_string()) # returns '91415732000793'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Examples
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from cnpj_dv import CnpjCheckDigits
|
|
155
|
+
|
|
156
|
+
# Calculate check digits for a CNPJ base
|
|
157
|
+
base = "914157320007"
|
|
158
|
+
check_digits = CnpjCheckDigits(base)
|
|
159
|
+
|
|
160
|
+
# Get individual check digits
|
|
161
|
+
first = check_digits.first_digit # 9
|
|
162
|
+
second = check_digits.second_digit # 3
|
|
163
|
+
|
|
164
|
+
# Get complete CNPJ
|
|
165
|
+
complete = check_digits.to_string() # '91415732000793'
|
|
166
|
+
|
|
167
|
+
# Work with formatted input
|
|
168
|
+
formatted = CnpjCheckDigits("91.415.732/0007")
|
|
169
|
+
print(formatted.to_string()) # '91415732000793'
|
|
170
|
+
|
|
171
|
+
# Work with list input
|
|
172
|
+
list_input = CnpjCheckDigits([9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7])
|
|
173
|
+
print(list_input.to_string()) # '91415732000793'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Error Handling
|
|
177
|
+
|
|
178
|
+
The package raises specific exceptions for different error scenarios:
|
|
179
|
+
|
|
180
|
+
### `CnpjTypeError`
|
|
181
|
+
|
|
182
|
+
Raised when the input type is not supported (must be `str`, `list[str]`, or `list[int]`).
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
from cnpj_dv import CnpjCheckDigits, CnpjTypeError
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
CnpjCheckDigits(12345678901234) # int not allowed
|
|
189
|
+
except CnpjTypeError as e:
|
|
190
|
+
print(e) # CNPJ input must be of type str, list[str] or list[int]. Got "int".
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### `CnpjInvalidLengthError`
|
|
194
|
+
|
|
195
|
+
Raised when the input does not contain 12 to 14 digits.
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from cnpj_dv import CnpjCheckDigits, CnpjInvalidLengthError
|
|
199
|
+
|
|
200
|
+
try:
|
|
201
|
+
CnpjCheckDigits("12345678901") # only 11 digits
|
|
202
|
+
except CnpjInvalidLengthError as e:
|
|
203
|
+
print(e) # Parameter "12345678901" does not contain 12 to 14 digits. Got 11.
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### `CnpjCheckDigitsCalculationError`
|
|
207
|
+
|
|
208
|
+
Raised when the check digit calculation fails due to invalid sequence length.
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
from cnpj_dv import CnpjCheckDigits, CnpjCheckDigitsCalculationError
|
|
212
|
+
|
|
213
|
+
# This is an internal error that should not occur in normal usage
|
|
214
|
+
# It happens when the sequence passed to _calculate() has invalid length
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Features
|
|
218
|
+
|
|
219
|
+
- ✅ **Multiple Input Formats**: Accepts strings, lists of strings, or lists of integers
|
|
220
|
+
- ✅ **Format Agnostic**: Automatically strips non-numeric characters from string input
|
|
221
|
+
- ✅ **Auto-Expansion**: Automatically expands multi-digit numbers in lists to individual digits
|
|
222
|
+
- ✅ **Lazy Evaluation**: Check digits are calculated only when accessed (via properties)
|
|
223
|
+
- ✅ **Type Safety**: Built with Python 3.10+ type hints
|
|
224
|
+
- ✅ **Zero Dependencies**: No external dependencies required
|
|
225
|
+
- ✅ **Comprehensive Error Handling**: Specific exceptions for different error scenarios
|
|
226
|
+
|
|
227
|
+
## API Reference
|
|
228
|
+
|
|
229
|
+
### CnpjCheckDigits Class
|
|
230
|
+
|
|
231
|
+
#### Constructor
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
CnpjCheckDigits(cnpj_digits: str | list[str] | list[int]) -> CnpjCheckDigits
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Creates a new `CnpjCheckDigits` instance from the provided CNPJ base digits.
|
|
238
|
+
|
|
239
|
+
**Parameters:**
|
|
240
|
+
- `cnpj_digits` (str | list[str] | list[int]): The CNPJ base digits (12-14 digits). Can be:
|
|
241
|
+
- A string with 12-14 digits (formatting characters are ignored)
|
|
242
|
+
- A list of strings (each string can be a single digit or multi-digit number)
|
|
243
|
+
- A list of integers (each integer can be a single digit or multi-digit number)
|
|
244
|
+
|
|
245
|
+
**Raises:**
|
|
246
|
+
- `CnpjTypeError`: If the input type is not supported
|
|
247
|
+
- `CnpjInvalidLengthError`: If the input does not contain 12-14 digits
|
|
248
|
+
|
|
249
|
+
**Returns:**
|
|
250
|
+
- `CnpjCheckDigits`: A new instance ready to calculate check digits
|
|
251
|
+
|
|
252
|
+
#### Properties
|
|
253
|
+
|
|
254
|
+
##### `first_digit: int`
|
|
255
|
+
|
|
256
|
+
The first check digit (13th digit of the CNPJ). Calculated lazily on first access.
|
|
257
|
+
|
|
258
|
+
##### `second_digit: int`
|
|
259
|
+
|
|
260
|
+
The second check digit (14th digit of the CNPJ). Calculated lazily on first access.
|
|
261
|
+
|
|
262
|
+
#### Methods
|
|
263
|
+
|
|
264
|
+
##### `to_list() -> list[int]`
|
|
265
|
+
|
|
266
|
+
Returns the complete CNPJ as a list of 14 integers (12 base digits + 2 check digits).
|
|
267
|
+
|
|
268
|
+
##### `to_string() -> str`
|
|
269
|
+
|
|
270
|
+
Returns the complete CNPJ as a string of 14 digits (12 base digits + 2 check digits).
|
|
271
|
+
|
|
272
|
+
## Calculation Algorithm
|
|
273
|
+
|
|
274
|
+
The package calculates CNPJ check digits using the official Brazilian algorithm:
|
|
275
|
+
|
|
276
|
+
1. **First Check Digit (13th position)**:
|
|
277
|
+
- Uses digits 1-12 of the CNPJ base
|
|
278
|
+
- Applies weights: 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 (from right to left)
|
|
279
|
+
- Calculates: `sum(digit × weight) % 11`
|
|
280
|
+
- Result: `0` if remainder < 2, otherwise `11 - remainder`
|
|
281
|
+
|
|
282
|
+
2. **Second Check Digit (14th position)**:
|
|
283
|
+
- Uses digits 1-12 + first check digit
|
|
284
|
+
- Applies weights: 6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 (from right to left)
|
|
285
|
+
- Calculates: `sum(digit × weight) % 11`
|
|
286
|
+
- Result: `0` if remainder < 2, otherwise `11 - remainder`
|
|
287
|
+
|
|
288
|
+
## Dependencies
|
|
289
|
+
|
|
290
|
+
- **Python**: >= 3.10
|
|
291
|
+
|
|
292
|
+
No external dependencies required.
|
|
293
|
+
|
|
294
|
+
## Contribution & Support
|
|
295
|
+
|
|
296
|
+
We welcome contributions! Please see our [Contributing Guidelines](https://github.com/LacusSolutions/br-utils-py/blob/main/CONTRIBUTING.md) for details. But if you find this project helpful, please consider:
|
|
297
|
+
|
|
298
|
+
- ⭐ Starring the repository
|
|
299
|
+
- 🤝 Contributing to the codebase
|
|
300
|
+
- 💡 [Suggesting new features](https://github.com/LacusSolutions/br-utils-py/issues)
|
|
301
|
+
- 🐛 [Reporting bugs](https://github.com/LacusSolutions/br-utils-py/issues)
|
|
302
|
+
|
|
303
|
+
## License
|
|
304
|
+
|
|
305
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/LacusSolutions/br-utils-py/blob/main/LICENSE) file for details.
|
|
306
|
+
|
|
307
|
+
## Changelog
|
|
308
|
+
|
|
309
|
+
See [CHANGELOG](https://github.com/LacusSolutions/br-utils-py/blob/main/packages/cnpj-dv/CHANGELOG.md) for a list of changes and version history.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
Made with ❤️ by [Lacus Solutions](https://github.com/LacusSolutions)
|
cnpj_dv-1.0.0/README.md
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/cnpj-dv)
|
|
4
|
+
[](https://pypi.org/project/cnpj-dv)
|
|
5
|
+
[](https://www.python.org/)
|
|
6
|
+
[](https://github.com/LacusSolutions/br-utils-py/actions)
|
|
7
|
+
[](https://github.com/LacusSolutions/br-utils-py)
|
|
8
|
+
[](https://github.com/LacusSolutions/br-utils-py/blob/main/LICENSE)
|
|
9
|
+
|
|
10
|
+
Utility class to calculate check digits on CNPJ (Brazilian employer ID).
|
|
11
|
+
|
|
12
|
+
## Python Support
|
|
13
|
+
|
|
14
|
+
|  |  |  |  |  |
|
|
15
|
+
|--- | --- | --- | --- | --- |
|
|
16
|
+
| Passing ✔ | Passing ✔ | Passing ✔ | Passing ✔ | Passing ✔ |
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
$ pip install cnpj-dv
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Import
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from cnpj_dv import CnpjCheckDigits
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
### Basic Usage
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
# Calculate check digits from a 12-digit CNPJ base
|
|
36
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
37
|
+
|
|
38
|
+
print(check_digits.first_digit) # returns 9
|
|
39
|
+
print(check_digits.second_digit) # returns 3
|
|
40
|
+
print(check_digits.to_string()) # returns '91415732000793'
|
|
41
|
+
print(check_digits.to_list()) # returns [9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7, 9, 3]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Input Formats
|
|
45
|
+
|
|
46
|
+
The `CnpjCheckDigits` class accepts multiple input formats:
|
|
47
|
+
|
|
48
|
+
#### String Input
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
# Plain string (non-numeric characters are automatically stripped)
|
|
52
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
53
|
+
check_digits = CnpjCheckDigits("91.415.732/0007") # formatting is ignored
|
|
54
|
+
check_digits = CnpjCheckDigits("914157320007") # 12 digits
|
|
55
|
+
check_digits = CnpjCheckDigits("91415732000793") # 14 digits (only first 12 are used)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### List of Strings
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
# List of single-character strings
|
|
62
|
+
check_digits = CnpjCheckDigits(["9", "1", "4", "1", "5", "7", "3", "2", "0", "0", "0", "7"])
|
|
63
|
+
|
|
64
|
+
# List with multi-digit strings (automatically flattened)
|
|
65
|
+
check_digits = CnpjCheckDigits(["914157320007"]) # flattens to individual digits
|
|
66
|
+
check_digits = CnpjCheckDigits(["91", "415", "732", "0007"]) # also flattens
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### List of Integers
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
# List of single-digit integers
|
|
73
|
+
check_digits = CnpjCheckDigits([9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7])
|
|
74
|
+
|
|
75
|
+
# List with multi-digit integers (automatically flattened)
|
|
76
|
+
check_digits = CnpjCheckDigits([914157320007]) # flattens to individual digits
|
|
77
|
+
check_digits = CnpjCheckDigits([914, 157, 320, 7]) # also flattens
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Properties
|
|
81
|
+
|
|
82
|
+
#### `first_digit: int`
|
|
83
|
+
|
|
84
|
+
Returns the first check digit (13th digit of the CNPJ).
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
88
|
+
print(check_digits.first_digit) # returns 9
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### `second_digit: int`
|
|
92
|
+
|
|
93
|
+
Returns the second check digit (14th digit of the CNPJ).
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
97
|
+
print(check_digits.second_digit) # returns 3
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Methods
|
|
101
|
+
|
|
102
|
+
#### `to_list() -> list[int]`
|
|
103
|
+
|
|
104
|
+
Returns the complete CNPJ as a list of integers (12 base digits + 2 check digits).
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
108
|
+
print(check_digits.to_list()) # returns [9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7, 9, 3]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### `to_string() -> str`
|
|
112
|
+
|
|
113
|
+
Returns the complete CNPJ as a string (12 base digits + 2 check digits).
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
117
|
+
print(check_digits.to_string()) # returns '91415732000793'
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Examples
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from cnpj_dv import CnpjCheckDigits
|
|
124
|
+
|
|
125
|
+
# Calculate check digits for a CNPJ base
|
|
126
|
+
base = "914157320007"
|
|
127
|
+
check_digits = CnpjCheckDigits(base)
|
|
128
|
+
|
|
129
|
+
# Get individual check digits
|
|
130
|
+
first = check_digits.first_digit # 9
|
|
131
|
+
second = check_digits.second_digit # 3
|
|
132
|
+
|
|
133
|
+
# Get complete CNPJ
|
|
134
|
+
complete = check_digits.to_string() # '91415732000793'
|
|
135
|
+
|
|
136
|
+
# Work with formatted input
|
|
137
|
+
formatted = CnpjCheckDigits("91.415.732/0007")
|
|
138
|
+
print(formatted.to_string()) # '91415732000793'
|
|
139
|
+
|
|
140
|
+
# Work with list input
|
|
141
|
+
list_input = CnpjCheckDigits([9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7])
|
|
142
|
+
print(list_input.to_string()) # '91415732000793'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Error Handling
|
|
146
|
+
|
|
147
|
+
The package raises specific exceptions for different error scenarios:
|
|
148
|
+
|
|
149
|
+
### `CnpjTypeError`
|
|
150
|
+
|
|
151
|
+
Raised when the input type is not supported (must be `str`, `list[str]`, or `list[int]`).
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from cnpj_dv import CnpjCheckDigits, CnpjTypeError
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
CnpjCheckDigits(12345678901234) # int not allowed
|
|
158
|
+
except CnpjTypeError as e:
|
|
159
|
+
print(e) # CNPJ input must be of type str, list[str] or list[int]. Got "int".
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### `CnpjInvalidLengthError`
|
|
163
|
+
|
|
164
|
+
Raised when the input does not contain 12 to 14 digits.
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from cnpj_dv import CnpjCheckDigits, CnpjInvalidLengthError
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
CnpjCheckDigits("12345678901") # only 11 digits
|
|
171
|
+
except CnpjInvalidLengthError as e:
|
|
172
|
+
print(e) # Parameter "12345678901" does not contain 12 to 14 digits. Got 11.
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### `CnpjCheckDigitsCalculationError`
|
|
176
|
+
|
|
177
|
+
Raised when the check digit calculation fails due to invalid sequence length.
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from cnpj_dv import CnpjCheckDigits, CnpjCheckDigitsCalculationError
|
|
181
|
+
|
|
182
|
+
# This is an internal error that should not occur in normal usage
|
|
183
|
+
# It happens when the sequence passed to _calculate() has invalid length
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Features
|
|
187
|
+
|
|
188
|
+
- ✅ **Multiple Input Formats**: Accepts strings, lists of strings, or lists of integers
|
|
189
|
+
- ✅ **Format Agnostic**: Automatically strips non-numeric characters from string input
|
|
190
|
+
- ✅ **Auto-Expansion**: Automatically expands multi-digit numbers in lists to individual digits
|
|
191
|
+
- ✅ **Lazy Evaluation**: Check digits are calculated only when accessed (via properties)
|
|
192
|
+
- ✅ **Type Safety**: Built with Python 3.10+ type hints
|
|
193
|
+
- ✅ **Zero Dependencies**: No external dependencies required
|
|
194
|
+
- ✅ **Comprehensive Error Handling**: Specific exceptions for different error scenarios
|
|
195
|
+
|
|
196
|
+
## API Reference
|
|
197
|
+
|
|
198
|
+
### CnpjCheckDigits Class
|
|
199
|
+
|
|
200
|
+
#### Constructor
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
CnpjCheckDigits(cnpj_digits: str | list[str] | list[int]) -> CnpjCheckDigits
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Creates a new `CnpjCheckDigits` instance from the provided CNPJ base digits.
|
|
207
|
+
|
|
208
|
+
**Parameters:**
|
|
209
|
+
- `cnpj_digits` (str | list[str] | list[int]): The CNPJ base digits (12-14 digits). Can be:
|
|
210
|
+
- A string with 12-14 digits (formatting characters are ignored)
|
|
211
|
+
- A list of strings (each string can be a single digit or multi-digit number)
|
|
212
|
+
- A list of integers (each integer can be a single digit or multi-digit number)
|
|
213
|
+
|
|
214
|
+
**Raises:**
|
|
215
|
+
- `CnpjTypeError`: If the input type is not supported
|
|
216
|
+
- `CnpjInvalidLengthError`: If the input does not contain 12-14 digits
|
|
217
|
+
|
|
218
|
+
**Returns:**
|
|
219
|
+
- `CnpjCheckDigits`: A new instance ready to calculate check digits
|
|
220
|
+
|
|
221
|
+
#### Properties
|
|
222
|
+
|
|
223
|
+
##### `first_digit: int`
|
|
224
|
+
|
|
225
|
+
The first check digit (13th digit of the CNPJ). Calculated lazily on first access.
|
|
226
|
+
|
|
227
|
+
##### `second_digit: int`
|
|
228
|
+
|
|
229
|
+
The second check digit (14th digit of the CNPJ). Calculated lazily on first access.
|
|
230
|
+
|
|
231
|
+
#### Methods
|
|
232
|
+
|
|
233
|
+
##### `to_list() -> list[int]`
|
|
234
|
+
|
|
235
|
+
Returns the complete CNPJ as a list of 14 integers (12 base digits + 2 check digits).
|
|
236
|
+
|
|
237
|
+
##### `to_string() -> str`
|
|
238
|
+
|
|
239
|
+
Returns the complete CNPJ as a string of 14 digits (12 base digits + 2 check digits).
|
|
240
|
+
|
|
241
|
+
## Calculation Algorithm
|
|
242
|
+
|
|
243
|
+
The package calculates CNPJ check digits using the official Brazilian algorithm:
|
|
244
|
+
|
|
245
|
+
1. **First Check Digit (13th position)**:
|
|
246
|
+
- Uses digits 1-12 of the CNPJ base
|
|
247
|
+
- Applies weights: 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 (from right to left)
|
|
248
|
+
- Calculates: `sum(digit × weight) % 11`
|
|
249
|
+
- Result: `0` if remainder < 2, otherwise `11 - remainder`
|
|
250
|
+
|
|
251
|
+
2. **Second Check Digit (14th position)**:
|
|
252
|
+
- Uses digits 1-12 + first check digit
|
|
253
|
+
- Applies weights: 6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 (from right to left)
|
|
254
|
+
- Calculates: `sum(digit × weight) % 11`
|
|
255
|
+
- Result: `0` if remainder < 2, otherwise `11 - remainder`
|
|
256
|
+
|
|
257
|
+
## Dependencies
|
|
258
|
+
|
|
259
|
+
- **Python**: >= 3.10
|
|
260
|
+
|
|
261
|
+
No external dependencies required.
|
|
262
|
+
|
|
263
|
+
## Contribution & Support
|
|
264
|
+
|
|
265
|
+
We welcome contributions! Please see our [Contributing Guidelines](https://github.com/LacusSolutions/br-utils-py/blob/main/CONTRIBUTING.md) for details. But if you find this project helpful, please consider:
|
|
266
|
+
|
|
267
|
+
- ⭐ Starring the repository
|
|
268
|
+
- 🤝 Contributing to the codebase
|
|
269
|
+
- 💡 [Suggesting new features](https://github.com/LacusSolutions/br-utils-py/issues)
|
|
270
|
+
- 🐛 [Reporting bugs](https://github.com/LacusSolutions/br-utils-py/issues)
|
|
271
|
+
|
|
272
|
+
## License
|
|
273
|
+
|
|
274
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/LacusSolutions/br-utils-py/blob/main/LICENSE) file for details.
|
|
275
|
+
|
|
276
|
+
## Changelog
|
|
277
|
+
|
|
278
|
+
See [CHANGELOG](https://github.com/LacusSolutions/br-utils-py/blob/main/packages/cnpj-dv/CHANGELOG.md) for a list of changes and version history.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
Made with ❤️ by [Lacus Solutions](https://github.com/LacusSolutions)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "cnpj-dv"
|
|
3
|
+
dynamic = [ "version" ]
|
|
4
|
+
description = "Utility resources to calculate check digits on CNPJ (Brazilian employer ID)"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
license-files = [ "LICENSE" ]
|
|
7
|
+
keywords = [
|
|
8
|
+
"cnpj",
|
|
9
|
+
"verificar",
|
|
10
|
+
"verificador",
|
|
11
|
+
"verify",
|
|
12
|
+
"verification",
|
|
13
|
+
"check",
|
|
14
|
+
"check-digit",
|
|
15
|
+
"check-digits",
|
|
16
|
+
"pt-br",
|
|
17
|
+
"br",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 5 - Production/Stable",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Natural Language :: English",
|
|
23
|
+
"Natural Language :: Portuguese (Brazilian)",
|
|
24
|
+
"Operating System :: MacOS :: MacOS X",
|
|
25
|
+
"Operating System :: Microsoft :: Windows",
|
|
26
|
+
"Operating System :: POSIX",
|
|
27
|
+
"Operating System :: Unix",
|
|
28
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
29
|
+
"Programming Language :: Python :: 3.10",
|
|
30
|
+
"Programming Language :: Python :: 3.11",
|
|
31
|
+
"Programming Language :: Python :: 3.12",
|
|
32
|
+
"Programming Language :: Python :: 3.13",
|
|
33
|
+
"Programming Language :: Python :: 3.14",
|
|
34
|
+
"Topic :: Software Development :: Libraries",
|
|
35
|
+
"Topic :: Utilities",
|
|
36
|
+
]
|
|
37
|
+
requires-python = ">=3.10"
|
|
38
|
+
|
|
39
|
+
[[project.authors]]
|
|
40
|
+
name = "Julio L. Muller"
|
|
41
|
+
|
|
42
|
+
[project.readme]
|
|
43
|
+
file = "README.md"
|
|
44
|
+
content-type = "text/markdown"
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Homepage = "https://cnpj-utils.vercel.app/"
|
|
48
|
+
Source = "https://github.com/LacusSolutions/br-utils-py"
|
|
49
|
+
Tracker = "https://github.com/LacusSolutions/br-utils-py/issues"
|
|
50
|
+
|
|
51
|
+
[build-system]
|
|
52
|
+
requires = [ "setuptools>=80.9.0", "wheel" ]
|
|
53
|
+
build-backend = "setuptools.build_meta"
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.dynamic.version]
|
|
56
|
+
attr = "cnpj_dv.__version__"
|
|
57
|
+
|
|
58
|
+
[tool.setuptools.packages.find]
|
|
59
|
+
where = [ "src/" ]
|
|
60
|
+
|
|
61
|
+
[tool.pytest.ini_options]
|
|
62
|
+
minversion = "9.0"
|
|
63
|
+
testpaths = [ "tests/" ]
|
|
64
|
+
python_files = [ "*_test.py" ]
|
|
65
|
+
python_functions = [ "test_*" ]
|
|
66
|
+
python_classes = [ "*Test" ]
|
|
67
|
+
|
|
68
|
+
[tool.coverage.run]
|
|
69
|
+
source = [ "src/" ]
|
|
70
|
+
omit = [ "tests/*" ]
|
cnpj_dv-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from .cnpj_check_digits import CnpjCheckDigits
|
|
2
|
+
from .exceptions import (
|
|
3
|
+
CnpjCheckDigitsCalculationError,
|
|
4
|
+
CnpjCheckDigitsError,
|
|
5
|
+
CnpjInvalidLengthError,
|
|
6
|
+
CnpjTypeError,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"CnpjCheckDigits",
|
|
11
|
+
"CnpjCheckDigitsCalculationError",
|
|
12
|
+
"CnpjCheckDigitsError",
|
|
13
|
+
"CnpjInvalidLengthError",
|
|
14
|
+
"CnpjTypeError",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
__version__ = "1.0.0"
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from .exceptions import (
|
|
4
|
+
CnpjCheckDigitsCalculationError,
|
|
5
|
+
CnpjInvalidLengthError,
|
|
6
|
+
CnpjTypeError,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
CNPJ_MIN_LENGTH = 12
|
|
10
|
+
CNPJ_MAX_LENGTH = 14
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CnpjCheckDigits:
|
|
14
|
+
"""Class to calculate CNPJ check digits."""
|
|
15
|
+
|
|
16
|
+
__slots__ = ("_cnpj_digits", "_first_digit", "_second_digit")
|
|
17
|
+
|
|
18
|
+
def __init__(self, cnpj_digits: str | list[str] | list[int]) -> None:
|
|
19
|
+
original_input = cnpj_digits
|
|
20
|
+
|
|
21
|
+
if not isinstance(cnpj_digits, (str, list)):
|
|
22
|
+
raise CnpjTypeError(original_input)
|
|
23
|
+
|
|
24
|
+
if isinstance(cnpj_digits, str):
|
|
25
|
+
cnpj_digits = self._handle_string_input(cnpj_digits, original_input)
|
|
26
|
+
elif isinstance(cnpj_digits, list):
|
|
27
|
+
cnpj_digits = self._handle_list_input(cnpj_digits, original_input)
|
|
28
|
+
|
|
29
|
+
self._validate_length(cnpj_digits, original_input)
|
|
30
|
+
self._cnpj_digits = cnpj_digits[:CNPJ_MIN_LENGTH]
|
|
31
|
+
self._first_digit: int | None = None
|
|
32
|
+
self._second_digit: int | None = None
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def first_digit(self) -> int:
|
|
36
|
+
"""Calculates and returns the first check digit.As it's immutable, it caches the calculation result."""
|
|
37
|
+
if self._first_digit is None:
|
|
38
|
+
base_digits_sequence = self._cnpj_digits.copy()
|
|
39
|
+
self._first_digit = self._calculate(base_digits_sequence)
|
|
40
|
+
|
|
41
|
+
return self._first_digit
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def second_digit(self) -> int:
|
|
45
|
+
"""Calculates and returns the second check digit.As it's immutable, it caches the calculation result. And, as it depends on the first check digit, it's also calculated."""
|
|
46
|
+
if self._second_digit is None:
|
|
47
|
+
base_digits_sequence = [*self._cnpj_digits, self.first_digit]
|
|
48
|
+
self._second_digit = self._calculate(base_digits_sequence)
|
|
49
|
+
|
|
50
|
+
return self._second_digit
|
|
51
|
+
|
|
52
|
+
def to_list(self) -> list[int]:
|
|
53
|
+
"""Returns the complete CNPJ as a list of 14 integers (12 base digits + 2 check digits)."""
|
|
54
|
+
return [*self._cnpj_digits, self.first_digit, self.second_digit]
|
|
55
|
+
|
|
56
|
+
def to_string(self) -> str:
|
|
57
|
+
"""Returns the complete CNPJ as a string of 14 digits (12 base digits + 2 check digits)."""
|
|
58
|
+
return "".join(str(digit) for digit in self.to_list())
|
|
59
|
+
|
|
60
|
+
def _handle_string_input(self, cnpj_digits: str, original_input: str) -> list[int]:
|
|
61
|
+
"""When CNPJ is provided as a string, it's validated and converted to a list of integers."""
|
|
62
|
+
numeric_str = re.sub(r"[^0-9]", "", cnpj_digits)
|
|
63
|
+
|
|
64
|
+
if not numeric_str:
|
|
65
|
+
raise CnpjInvalidLengthError(
|
|
66
|
+
original_input, CNPJ_MIN_LENGTH, CNPJ_MAX_LENGTH, 0
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
return [int(d) for d in numeric_str]
|
|
70
|
+
|
|
71
|
+
def _handle_list_input(
|
|
72
|
+
self, cnpj_digits: list[str] | list[int], original_input: list
|
|
73
|
+
) -> list[int]:
|
|
74
|
+
"""When CNPJ is provided as a list of strings or integers, it's validated and converted to a list of integers for further processing."""
|
|
75
|
+
if all(isinstance(digit, str) for digit in cnpj_digits):
|
|
76
|
+
return self._handle_string_list(cnpj_digits, original_input)
|
|
77
|
+
|
|
78
|
+
if all(isinstance(digit, int) for digit in cnpj_digits):
|
|
79
|
+
return self._flatten_digits(cnpj_digits)
|
|
80
|
+
|
|
81
|
+
raise CnpjTypeError(original_input)
|
|
82
|
+
|
|
83
|
+
def _handle_string_list(
|
|
84
|
+
self, cnpj_digits: list[str], original_input: list
|
|
85
|
+
) -> list[int]:
|
|
86
|
+
"""When CNPJ is provided as a list of strings, it's validated and converted to a list of integers for further processing."""
|
|
87
|
+
total_length = sum(len(digit_str) for digit_str in cnpj_digits if digit_str)
|
|
88
|
+
|
|
89
|
+
if total_length < CNPJ_MIN_LENGTH or total_length > CNPJ_MAX_LENGTH:
|
|
90
|
+
raise CnpjInvalidLengthError(
|
|
91
|
+
original_input, CNPJ_MIN_LENGTH, CNPJ_MAX_LENGTH, total_length
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
flat_digits = []
|
|
95
|
+
|
|
96
|
+
for digit_str in cnpj_digits:
|
|
97
|
+
if not digit_str:
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
digit_int = int(digit_str)
|
|
102
|
+
flat_digits.extend(self._flatten_digits([digit_int]))
|
|
103
|
+
except ValueError as e:
|
|
104
|
+
raise CnpjTypeError(original_input) from e
|
|
105
|
+
|
|
106
|
+
return flat_digits
|
|
107
|
+
|
|
108
|
+
def _flatten_digits(self, digits: list[int]) -> list[int]:
|
|
109
|
+
"""Breaks down multiple digits within the array into individual digits. Negative numbers are converted to their absolute value."""
|
|
110
|
+
flat_digits = []
|
|
111
|
+
|
|
112
|
+
for digit in digits:
|
|
113
|
+
abs_digit = abs(digit)
|
|
114
|
+
flat_digits.extend([int(d) for d in str(abs_digit)])
|
|
115
|
+
|
|
116
|
+
return flat_digits
|
|
117
|
+
|
|
118
|
+
def _validate_length(
|
|
119
|
+
self, cnpj_digits: list[int], original_input: str | list
|
|
120
|
+
) -> None:
|
|
121
|
+
"""Validates the length of the CNPJ digits."""
|
|
122
|
+
length = len(cnpj_digits)
|
|
123
|
+
|
|
124
|
+
if length < CNPJ_MIN_LENGTH or length > CNPJ_MAX_LENGTH:
|
|
125
|
+
raise CnpjInvalidLengthError(
|
|
126
|
+
original_input, CNPJ_MIN_LENGTH, CNPJ_MAX_LENGTH, length
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def _calculate(self, cnpj_sequence: list[int]) -> int:
|
|
130
|
+
"""Calculates the CNPJ check digits using the official Brazilian algorithm. For the first check digit, it uses the digits 1 through 12 of the CNPJ base. For the second one, it uses the digits 1 through 13 (with the first check digit)."""
|
|
131
|
+
min_length = CNPJ_MIN_LENGTH
|
|
132
|
+
max_length = CNPJ_MAX_LENGTH - 1
|
|
133
|
+
sequence_length = len(cnpj_sequence)
|
|
134
|
+
|
|
135
|
+
if sequence_length < min_length or sequence_length > max_length:
|
|
136
|
+
raise CnpjCheckDigitsCalculationError(cnpj_sequence)
|
|
137
|
+
|
|
138
|
+
factor = 2
|
|
139
|
+
sum_result = 0
|
|
140
|
+
|
|
141
|
+
for num in reversed(cnpj_sequence):
|
|
142
|
+
sum_result += num * factor
|
|
143
|
+
factor = 2 if factor == 9 else factor + 1
|
|
144
|
+
|
|
145
|
+
remainder = sum_result % 11
|
|
146
|
+
|
|
147
|
+
return 0 if remainder < 2 else 11 - remainder
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class CnpjCheckDigitsError(Exception):
|
|
2
|
+
"""Base exception for all cnpj-dv related errors."""
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CnpjTypeError(CnpjCheckDigitsError):
|
|
6
|
+
"""Raised when a CNPJ digits is not a string or a list of strings or integers."""
|
|
7
|
+
|
|
8
|
+
def __init__(self, cnpj) -> None:
|
|
9
|
+
self.cnpj = cnpj
|
|
10
|
+
|
|
11
|
+
super().__init__(
|
|
12
|
+
f"CNPJ input must be of type str, list[str] or list[int]. Got {type(cnpj).__name__}."
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CnpjInvalidLengthError(CnpjCheckDigitsError):
|
|
17
|
+
"""Raised when a CNPJ string does not contain the expected number of digits."""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
cnpj: str | list[str] | list[int],
|
|
22
|
+
min_expected_length: int,
|
|
23
|
+
max_expected_length: int,
|
|
24
|
+
actual_length: int,
|
|
25
|
+
) -> None:
|
|
26
|
+
self.cnpj = cnpj
|
|
27
|
+
self.min_expected_length = min_expected_length
|
|
28
|
+
self.max_expected_length = max_expected_length
|
|
29
|
+
self.actual_length = actual_length
|
|
30
|
+
|
|
31
|
+
super().__init__(
|
|
32
|
+
f'Parameter "{cnpj}" does not contain {min_expected_length} to {max_expected_length} digits. '
|
|
33
|
+
f"Got {actual_length}."
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class CnpjCheckDigitsCalculationError(CnpjCheckDigitsError):
|
|
38
|
+
"""Raised when the calculation of the CNPJ check digits fails."""
|
|
39
|
+
|
|
40
|
+
def __init__(self, cnpj_digits: list[int]) -> None:
|
|
41
|
+
self.cnpj_digits = cnpj_digits
|
|
42
|
+
|
|
43
|
+
super().__init__(
|
|
44
|
+
f"Failed to calculate the CNPJ check digits for the sequence: {cnpj_digits}."
|
|
45
|
+
)
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cnpj-dv
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Utility resources to calculate check digits on CNPJ (Brazilian employer ID)
|
|
5
|
+
Author: Julio L. Muller
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://cnpj-utils.vercel.app/
|
|
8
|
+
Project-URL: Source, https://github.com/LacusSolutions/br-utils-py
|
|
9
|
+
Project-URL: Tracker, https://github.com/LacusSolutions/br-utils-py/issues
|
|
10
|
+
Keywords: cnpj,verificar,verificador,verify,verification,check,check-digit,check-digits,pt-br,br
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Natural Language :: Portuguese (Brazilian)
|
|
15
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX
|
|
18
|
+
Classifier: Operating System :: Unix
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
26
|
+
Classifier: Topic :: Utilities
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/cnpj-dv)
|
|
35
|
+
[](https://pypi.org/project/cnpj-dv)
|
|
36
|
+
[](https://www.python.org/)
|
|
37
|
+
[](https://github.com/LacusSolutions/br-utils-py/actions)
|
|
38
|
+
[](https://github.com/LacusSolutions/br-utils-py)
|
|
39
|
+
[](https://github.com/LacusSolutions/br-utils-py/blob/main/LICENSE)
|
|
40
|
+
|
|
41
|
+
Utility class to calculate check digits on CNPJ (Brazilian employer ID).
|
|
42
|
+
|
|
43
|
+
## Python Support
|
|
44
|
+
|
|
45
|
+
|  |  |  |  |  |
|
|
46
|
+
|--- | --- | --- | --- | --- |
|
|
47
|
+
| Passing ✔ | Passing ✔ | Passing ✔ | Passing ✔ | Passing ✔ |
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
$ pip install cnpj-dv
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Import
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from cnpj_dv import CnpjCheckDigits
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
|
|
63
|
+
### Basic Usage
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
# Calculate check digits from a 12-digit CNPJ base
|
|
67
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
68
|
+
|
|
69
|
+
print(check_digits.first_digit) # returns 9
|
|
70
|
+
print(check_digits.second_digit) # returns 3
|
|
71
|
+
print(check_digits.to_string()) # returns '91415732000793'
|
|
72
|
+
print(check_digits.to_list()) # returns [9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7, 9, 3]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Input Formats
|
|
76
|
+
|
|
77
|
+
The `CnpjCheckDigits` class accepts multiple input formats:
|
|
78
|
+
|
|
79
|
+
#### String Input
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
# Plain string (non-numeric characters are automatically stripped)
|
|
83
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
84
|
+
check_digits = CnpjCheckDigits("91.415.732/0007") # formatting is ignored
|
|
85
|
+
check_digits = CnpjCheckDigits("914157320007") # 12 digits
|
|
86
|
+
check_digits = CnpjCheckDigits("91415732000793") # 14 digits (only first 12 are used)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### List of Strings
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# List of single-character strings
|
|
93
|
+
check_digits = CnpjCheckDigits(["9", "1", "4", "1", "5", "7", "3", "2", "0", "0", "0", "7"])
|
|
94
|
+
|
|
95
|
+
# List with multi-digit strings (automatically flattened)
|
|
96
|
+
check_digits = CnpjCheckDigits(["914157320007"]) # flattens to individual digits
|
|
97
|
+
check_digits = CnpjCheckDigits(["91", "415", "732", "0007"]) # also flattens
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### List of Integers
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
# List of single-digit integers
|
|
104
|
+
check_digits = CnpjCheckDigits([9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7])
|
|
105
|
+
|
|
106
|
+
# List with multi-digit integers (automatically flattened)
|
|
107
|
+
check_digits = CnpjCheckDigits([914157320007]) # flattens to individual digits
|
|
108
|
+
check_digits = CnpjCheckDigits([914, 157, 320, 7]) # also flattens
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Properties
|
|
112
|
+
|
|
113
|
+
#### `first_digit: int`
|
|
114
|
+
|
|
115
|
+
Returns the first check digit (13th digit of the CNPJ).
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
119
|
+
print(check_digits.first_digit) # returns 9
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### `second_digit: int`
|
|
123
|
+
|
|
124
|
+
Returns the second check digit (14th digit of the CNPJ).
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
128
|
+
print(check_digits.second_digit) # returns 3
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Methods
|
|
132
|
+
|
|
133
|
+
#### `to_list() -> list[int]`
|
|
134
|
+
|
|
135
|
+
Returns the complete CNPJ as a list of integers (12 base digits + 2 check digits).
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
139
|
+
print(check_digits.to_list()) # returns [9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7, 9, 3]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### `to_string() -> str`
|
|
143
|
+
|
|
144
|
+
Returns the complete CNPJ as a string (12 base digits + 2 check digits).
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
check_digits = CnpjCheckDigits("914157320007")
|
|
148
|
+
print(check_digits.to_string()) # returns '91415732000793'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Examples
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from cnpj_dv import CnpjCheckDigits
|
|
155
|
+
|
|
156
|
+
# Calculate check digits for a CNPJ base
|
|
157
|
+
base = "914157320007"
|
|
158
|
+
check_digits = CnpjCheckDigits(base)
|
|
159
|
+
|
|
160
|
+
# Get individual check digits
|
|
161
|
+
first = check_digits.first_digit # 9
|
|
162
|
+
second = check_digits.second_digit # 3
|
|
163
|
+
|
|
164
|
+
# Get complete CNPJ
|
|
165
|
+
complete = check_digits.to_string() # '91415732000793'
|
|
166
|
+
|
|
167
|
+
# Work with formatted input
|
|
168
|
+
formatted = CnpjCheckDigits("91.415.732/0007")
|
|
169
|
+
print(formatted.to_string()) # '91415732000793'
|
|
170
|
+
|
|
171
|
+
# Work with list input
|
|
172
|
+
list_input = CnpjCheckDigits([9, 1, 4, 1, 5, 7, 3, 2, 0, 0, 0, 7])
|
|
173
|
+
print(list_input.to_string()) # '91415732000793'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Error Handling
|
|
177
|
+
|
|
178
|
+
The package raises specific exceptions for different error scenarios:
|
|
179
|
+
|
|
180
|
+
### `CnpjTypeError`
|
|
181
|
+
|
|
182
|
+
Raised when the input type is not supported (must be `str`, `list[str]`, or `list[int]`).
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
from cnpj_dv import CnpjCheckDigits, CnpjTypeError
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
CnpjCheckDigits(12345678901234) # int not allowed
|
|
189
|
+
except CnpjTypeError as e:
|
|
190
|
+
print(e) # CNPJ input must be of type str, list[str] or list[int]. Got "int".
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### `CnpjInvalidLengthError`
|
|
194
|
+
|
|
195
|
+
Raised when the input does not contain 12 to 14 digits.
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from cnpj_dv import CnpjCheckDigits, CnpjInvalidLengthError
|
|
199
|
+
|
|
200
|
+
try:
|
|
201
|
+
CnpjCheckDigits("12345678901") # only 11 digits
|
|
202
|
+
except CnpjInvalidLengthError as e:
|
|
203
|
+
print(e) # Parameter "12345678901" does not contain 12 to 14 digits. Got 11.
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### `CnpjCheckDigitsCalculationError`
|
|
207
|
+
|
|
208
|
+
Raised when the check digit calculation fails due to invalid sequence length.
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
from cnpj_dv import CnpjCheckDigits, CnpjCheckDigitsCalculationError
|
|
212
|
+
|
|
213
|
+
# This is an internal error that should not occur in normal usage
|
|
214
|
+
# It happens when the sequence passed to _calculate() has invalid length
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Features
|
|
218
|
+
|
|
219
|
+
- ✅ **Multiple Input Formats**: Accepts strings, lists of strings, or lists of integers
|
|
220
|
+
- ✅ **Format Agnostic**: Automatically strips non-numeric characters from string input
|
|
221
|
+
- ✅ **Auto-Expansion**: Automatically expands multi-digit numbers in lists to individual digits
|
|
222
|
+
- ✅ **Lazy Evaluation**: Check digits are calculated only when accessed (via properties)
|
|
223
|
+
- ✅ **Type Safety**: Built with Python 3.10+ type hints
|
|
224
|
+
- ✅ **Zero Dependencies**: No external dependencies required
|
|
225
|
+
- ✅ **Comprehensive Error Handling**: Specific exceptions for different error scenarios
|
|
226
|
+
|
|
227
|
+
## API Reference
|
|
228
|
+
|
|
229
|
+
### CnpjCheckDigits Class
|
|
230
|
+
|
|
231
|
+
#### Constructor
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
CnpjCheckDigits(cnpj_digits: str | list[str] | list[int]) -> CnpjCheckDigits
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Creates a new `CnpjCheckDigits` instance from the provided CNPJ base digits.
|
|
238
|
+
|
|
239
|
+
**Parameters:**
|
|
240
|
+
- `cnpj_digits` (str | list[str] | list[int]): The CNPJ base digits (12-14 digits). Can be:
|
|
241
|
+
- A string with 12-14 digits (formatting characters are ignored)
|
|
242
|
+
- A list of strings (each string can be a single digit or multi-digit number)
|
|
243
|
+
- A list of integers (each integer can be a single digit or multi-digit number)
|
|
244
|
+
|
|
245
|
+
**Raises:**
|
|
246
|
+
- `CnpjTypeError`: If the input type is not supported
|
|
247
|
+
- `CnpjInvalidLengthError`: If the input does not contain 12-14 digits
|
|
248
|
+
|
|
249
|
+
**Returns:**
|
|
250
|
+
- `CnpjCheckDigits`: A new instance ready to calculate check digits
|
|
251
|
+
|
|
252
|
+
#### Properties
|
|
253
|
+
|
|
254
|
+
##### `first_digit: int`
|
|
255
|
+
|
|
256
|
+
The first check digit (13th digit of the CNPJ). Calculated lazily on first access.
|
|
257
|
+
|
|
258
|
+
##### `second_digit: int`
|
|
259
|
+
|
|
260
|
+
The second check digit (14th digit of the CNPJ). Calculated lazily on first access.
|
|
261
|
+
|
|
262
|
+
#### Methods
|
|
263
|
+
|
|
264
|
+
##### `to_list() -> list[int]`
|
|
265
|
+
|
|
266
|
+
Returns the complete CNPJ as a list of 14 integers (12 base digits + 2 check digits).
|
|
267
|
+
|
|
268
|
+
##### `to_string() -> str`
|
|
269
|
+
|
|
270
|
+
Returns the complete CNPJ as a string of 14 digits (12 base digits + 2 check digits).
|
|
271
|
+
|
|
272
|
+
## Calculation Algorithm
|
|
273
|
+
|
|
274
|
+
The package calculates CNPJ check digits using the official Brazilian algorithm:
|
|
275
|
+
|
|
276
|
+
1. **First Check Digit (13th position)**:
|
|
277
|
+
- Uses digits 1-12 of the CNPJ base
|
|
278
|
+
- Applies weights: 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 (from right to left)
|
|
279
|
+
- Calculates: `sum(digit × weight) % 11`
|
|
280
|
+
- Result: `0` if remainder < 2, otherwise `11 - remainder`
|
|
281
|
+
|
|
282
|
+
2. **Second Check Digit (14th position)**:
|
|
283
|
+
- Uses digits 1-12 + first check digit
|
|
284
|
+
- Applies weights: 6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 (from right to left)
|
|
285
|
+
- Calculates: `sum(digit × weight) % 11`
|
|
286
|
+
- Result: `0` if remainder < 2, otherwise `11 - remainder`
|
|
287
|
+
|
|
288
|
+
## Dependencies
|
|
289
|
+
|
|
290
|
+
- **Python**: >= 3.10
|
|
291
|
+
|
|
292
|
+
No external dependencies required.
|
|
293
|
+
|
|
294
|
+
## Contribution & Support
|
|
295
|
+
|
|
296
|
+
We welcome contributions! Please see our [Contributing Guidelines](https://github.com/LacusSolutions/br-utils-py/blob/main/CONTRIBUTING.md) for details. But if you find this project helpful, please consider:
|
|
297
|
+
|
|
298
|
+
- ⭐ Starring the repository
|
|
299
|
+
- 🤝 Contributing to the codebase
|
|
300
|
+
- 💡 [Suggesting new features](https://github.com/LacusSolutions/br-utils-py/issues)
|
|
301
|
+
- 🐛 [Reporting bugs](https://github.com/LacusSolutions/br-utils-py/issues)
|
|
302
|
+
|
|
303
|
+
## License
|
|
304
|
+
|
|
305
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/LacusSolutions/br-utils-py/blob/main/LICENSE) file for details.
|
|
306
|
+
|
|
307
|
+
## Changelog
|
|
308
|
+
|
|
309
|
+
See [CHANGELOG](https://github.com/LacusSolutions/br-utils-py/blob/main/packages/cnpj-dv/CHANGELOG.md) for a list of changes and version history.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
Made with ❤️ by [Lacus Solutions](https://github.com/LacusSolutions)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/cnpj_dv/__init__.py
|
|
5
|
+
src/cnpj_dv/cnpj_check_digits.py
|
|
6
|
+
src/cnpj_dv/exceptions.py
|
|
7
|
+
src/cnpj_dv.egg-info/PKG-INFO
|
|
8
|
+
src/cnpj_dv.egg-info/SOURCES.txt
|
|
9
|
+
src/cnpj_dv.egg-info/dependency_links.txt
|
|
10
|
+
src/cnpj_dv.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cnpj_dv
|