lists.arthurdejong.org
RSS feed

python-stdnum branch master updated. 2.1-21-gd3ec3bd

[Date Prev][Date Next] [Thread Prev][Thread Next]

python-stdnum branch master updated. 2.1-21-gd3ec3bd



This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-stdnum".

The branch, master has been updated
       via  d3ec3bd7fefe0d0a708b6594a66de28777eb9b8d (commit)
      from  cd94bf1147508a5132f0439e8d6c1ed3e2a7e14f (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://arthurdejong.org/git/python-stdnum/commit/?id=d3ec3bd7fefe0d0a708b6594a66de28777eb9b8d

commit d3ec3bd7fefe0d0a708b6594a66de28777eb9b8d
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sat Jan 3 15:32:23 2026 +0100

    Support new format for Brazilian CNPJ
    
    The new format allows letters as well as numbers to identify companies.
    
    Closes https://github.com/arthurdejong/python-stdnum/issues/484

diff --git a/stdnum/br/cnpj.py b/stdnum/br/cnpj.py
index 3178bec..ede9d7d 100644
--- a/stdnum/br/cnpj.py
+++ b/stdnum/br/cnpj.py
@@ -1,7 +1,7 @@
 # cnpj.py - functions for handling CNPJ numbers
 # coding: utf-8
 #
-# Copyright (C) 2015 Arthur de Jong
+# Copyright (C) 2015-2026 Arthur de Jong
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -20,12 +20,14 @@
 
 """CNPJ (Cadastro Nacional da Pessoa Jurídica, Brazilian company identifier).
 
-Numbers from the national register of legal entities have 14 digits. The
-first 8 digits identify the company, the following 4 digits identify a
+Numbers from the national register of legal entities have 14 alphanumeric 
digits.
+The first 8 digits identify the company, the following 4 digits identify a
 business unit and the last 2 digits are check digits.
 
 >>> validate('16.727.230/0001-97')
 '16727230000197'
+>>> validate('12. ABC.345 /01DE–35')  # new format from July 2026 onwards
+'12ABC34501DE35'
 >>> validate('16.727.230.0001-98')
 Traceback (most recent call last):
     ...
@@ -40,31 +42,39 @@ InvalidFormat: ...
 
 from __future__ import annotations
 
+import re
+
 from stdnum.exceptions import *
-from stdnum.util import clean, isdigits
+from stdnum.util import clean
+
+
+# Minimal regex of valid characters
+_cnpj_re = re.compile(r'^[\dA-Z]+$')
 
 
 def compact(number: str) -> str:
     """Convert the number to the minimal representation. This strips the
     number of any valid separators and removes surrounding whitespace."""
-    return clean(number, ' -./').strip()
+    return clean(number, ' -./').strip().upper()
 
 
 def calc_check_digits(number: str) -> str:
     """Calculate the check digits for the number."""
-    d1 = (11 - sum(((3 - i) % 8 + 2) * int(n)
-                   for i, n in enumerate(number[:12]))) % 11 % 10
-    d2 = (11 - sum(((4 - i) % 8 + 2) * int(n)
-                   for i, n in enumerate(number[:12])) -
-          2 * d1) % 11 % 10
-    return '%d%d' % (d1, d2)
+    number = compact(number)
+    values = [ord(n) - 48 for n in number[:12]]
+    weights = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
+    d1 = (11 - sum(w * v for w, v in zip(weights, values))) % 11 % 10
+    values.append(d1)
+    weights = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
+    d2 = (11 - sum(w * v for w, v in zip(weights, values))) % 11 % 10
+    return f'{d1}{d2}'
 
 
 def validate(number: str) -> str:
     """Check if the number is a valid CNPJ. This checks the length and
     whether the check digits are correct."""
     number = compact(number)
-    if not isdigits(number) or int(number) <= 0:
+    if not _cnpj_re.match(number) or number.startswith('000000000000'):
         raise InvalidFormat()
     if len(number) != 14:
         raise InvalidLength()

-----------------------------------------------------------------------

Summary of changes:
 stdnum/br/cnpj.py | 34 ++++++++++++++++++++++------------
 1 file changed, 22 insertions(+), 12 deletions(-)


hooks/post-receive
-- 
python-stdnum