python-stdnum branch master updated. 2.1-9-ge741318
[
Date Prev][
Date Next]
[
Thread Prev][
Thread Next]
python-stdnum branch master updated. 2.1-9-ge741318
- From: Commits of the python-stdnum project <python-stdnum-commits [at] lists.arthurdejong.org>
- To: python-stdnum-commits [at] lists.arthurdejong.org
- Reply-to: python-stdnum-users [at] lists.arthurdejong.org, python-stdnum-commits [at] lists.arthurdejong.org
- Subject: python-stdnum branch master updated. 2.1-9-ge741318
- Date: Sat, 23 Aug 2025 14:05:41 +0200 (CEST)
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 e741318e61f5c59c97ef0a0b6e1dbb3c2fd7b389 (commit)
via ca80cc42d0c6cec9473ae90dc49ce4d518f80f16 (commit)
via b3a42a15502370ea38d3b0c9a81017b99c2b7ecc (commit)
from 843bbece41aa12b8d3557d2c83ed7de124e359bb (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=e741318e61f5c59c97ef0a0b6e1dbb3c2fd7b389
commit e741318e61f5c59c97ef0a0b6e1dbb3c2fd7b389
Author: Fabien MICHEL <fmichel@adista.fr>
Date: Fri Aug 8 12:26:38 2025 +0200
Add French RCS number
Closes https://github.com/arthurdejong/python-stdnum/pull/481
diff --git a/stdnum/fr/rcs.py b/stdnum/fr/rcs.py
new file mode 100644
index 0000000..cc4ad27
--- /dev/null
+++ b/stdnum/fr/rcs.py
@@ -0,0 +1,117 @@
+# rcs.py - functions for handling French NIR numbers
+# coding: utf-8
+#
+# Copyright (C) 2025 Fabien Michel
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+"""RCS (French trade registration number for commercial companies).
+
+The RCS number (Registre du commerce et des sociétés) is given by INSEE to a
+company with commercial activity when created. It is required for most of
+administrative procedures.
+
+The number consists of "RCS" letters followed by name of the city where the
company was registered
+followed by letter A for a retailer or B for society
+followed by the SIREN number
+
+More information:
+
+* https://entreprendre.service-public.fr/vosdroits/F31190
+* https://fr.wikipedia.org/wiki/Registre_du_commerce_et_des_sociétés_(France)
+
+>>> validate('RCS Nancy B 323 159 715')
+'RCS Nancy B 323159715'
+>>> validate('RCS Nancy B 323 159 716')
+Traceback (most recent call last):
+ ...
+InvalidChecksum: ...
+>>> validate('RCSNancy B 323 159 716')
+Traceback (most recent call last):
+ ...
+InvalidFormat: ...
+>>> format('RCS Nancy B323159715')
+'RCS Nancy B 323 159 715'
+>>> to_siren('RCS Nancy B 323159 715')
+'323159715'
+"""
+
+from __future__ import annotations
+
+import re
+
+from stdnum.exceptions import *
+from stdnum.fr import siren
+from stdnum.util import clean
+
+
+_rcs_validation_regex = re.compile(
+ r'^ *(?P<tag>RCS|rcs) +(?P<city>.*?) +(?P<letter>[AB]) *(?P<siren>(?:\d
*){9})\b *$',
+)
+
+
+def compact(number: str) -> str:
+ """Convert the number to the minimal representation."""
+ parts = clean(number).strip().split()
+ rest = ''.join(parts[2:])
+ return ' '.join(parts[:2] + [rest[:1], siren.compact(rest[1:])])
+
+
+def validate(number: str) -> str:
+ """Validate number is a valid French RCS number."""
+ number = compact(number)
+ match = _rcs_validation_regex.match(number)
+ if not match:
+ raise InvalidFormat()
+ siren_number = siren.validate(match.group('siren'))
+ siren_number = siren.format(siren_number)
+ return number
+
+
+def is_valid(number: str) -> bool:
+ """Check if the number provided is valid."""
+ try:
+ return bool(validate(number))
+ except ValidationError:
+ return False
+
+
+def format(number: str) -> str:
+ """Reformat the number to the standard presentation format."""
+ number = compact(number)
+ match = _rcs_validation_regex.match(number)
+ if not match:
+ raise InvalidFormat()
+ return ' '.join(
+ (
+ 'RCS',
+ match.group('city'),
+ match.group('letter'),
+ siren.format(match.group('siren')),
+ ),
+ )
+
+
+def to_siren(number: str) -> str:
+ """Extract SIREN number from the RCS number.
+
+ The SIREN number is the 9 last digits of the RCS number.
+ """
+ number = compact(number)
+ match = _rcs_validation_regex.match(clean(number))
+ if not match:
+ raise InvalidFormat()
+ return match.group('siren')
diff --git a/tests/test_fr_rcs.doctest b/tests/test_fr_rcs.doctest
new file mode 100644
index 0000000..1dbdbfc
--- /dev/null
+++ b/tests/test_fr_rcs.doctest
@@ -0,0 +1,56 @@
+test_fr_rcs.doctest - more detailed doctests for the stdnum.fr.rcs module
+
+Copyright (C) 2025 Fabien Michel
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA
+
+
+This file contains more detailed doctests for the stdnum.fr.rcs module.
+
+>>> from stdnum.fr import rcs
+>>> from stdnum.exceptions import *
+
+
+>>> rcs.validate('RCS Nancy B 323 159 715')
+'RCS Nancy B 323159715'
+>>> rcs.validate('RCS Nancy B 323159715')
+'RCS Nancy B 323159715'
+>>> rcs.validate('RCS Nancy B323 159715')
+'RCS Nancy B 323159715'
+>>> rcs.validate('RCS Nancy B 323 159 716')
+Traceback (most recent call last):
+ ...
+InvalidChecksum: ...
+>>> rcs.validate('RCSNancy B 323 159 716')
+Traceback (most recent call last):
+ ...
+InvalidFormat: ...
+>>> rcs.validate('RCS NancyB 323 159 716')
+Traceback (most recent call last):
+ ...
+InvalidFormat: ...
+>>> rcs.format('RCS Nancy B323159715')
+'RCS Nancy B 323 159 715'
+>>> rcs.format('invalid')
+Traceback (most recent call last):
+ ...
+InvalidFormat: ...
+>>> rcs.to_siren('RCS Nancy B 323159 715')
+'323159715'
+>>> rcs.to_siren('invalid')
+Traceback (most recent call last):
+ ...
+InvalidFormat: ...
https://arthurdejong.org/git/python-stdnum/commit/?id=ca80cc42d0c6cec9473ae90dc49ce4d518f80f16
commit ca80cc42d0c6cec9473ae90dc49ce4d518f80f16
Author: Fabien MICHEL <fmichel@adista.fr>
Date: Fri Aug 8 10:47:14 2025 +0200
Add fr.siren.format() function
diff --git a/stdnum/fr/siren.py b/stdnum/fr/siren.py
index e360747..f1510ea 100644
--- a/stdnum/fr/siren.py
+++ b/stdnum/fr/siren.py
@@ -34,6 +34,8 @@ Traceback (most recent call last):
InvalidChecksum: ...
>>> to_tva('443 121 975')
'46 443 121 975'
+>>> format('404833048')
+'404 833 048'
"""
from __future__ import annotations
@@ -83,3 +85,9 @@ def to_tva(number: str) -> str:
int(compact(number) + '12') % 97,
' ' if ' ' in number else '',
number)
+
+
+def format(number: str, separator: str = ' ') -> str:
+ """Reformat the number to the standard presentation format."""
+ number = compact(number)
+ return separator.join((number[:3], number[3:6], number[6:]))
https://arthurdejong.org/git/python-stdnum/commit/?id=b3a42a15502370ea38d3b0c9a81017b99c2b7ecc
commit b3a42a15502370ea38d3b0c9a81017b99c2b7ecc
Author: Fabien MICHEL <fmichel@adista.fr>
Date: Fri Aug 8 09:16:56 2025 +0200
Add fr.tva.to_siren() function
The function can convert a French VAT number to a SIREN.
Closes https://github.com/arthurdejong/python-stdnum/pull/480
diff --git a/stdnum/fr/tva.py b/stdnum/fr/tva.py
index 2638663..faba6bc 100644
--- a/stdnum/fr/tva.py
+++ b/stdnum/fr/tva.py
@@ -41,6 +41,8 @@ InvalidChecksum: ...
Traceback (most recent call last):
...
InvalidFormat: ...
+>>> to_siren('Fr 40 303 265 045')
+'303265045'
"""
from __future__ import annotations
@@ -101,3 +103,15 @@ def is_valid(number: str) -> bool:
return bool(validate(number))
except ValidationError:
return False
+
+
+def to_siren(number: str) -> str:
+ """Convert the VAT number to a SIREN number.
+
+ The SIREN number is the 9 last digits of the VAT number.
+ """
+ number = compact(number)
+ if number[2:5] == '000':
+ # numbers from Monaco are valid TVA but not SIREN
+ raise InvalidComponent()
+ return number[2:]
diff --git a/tests/test_fr_tva.doctest b/tests/test_fr_tva.doctest
new file mode 100644
index 0000000..0c1e311
--- /dev/null
+++ b/tests/test_fr_tva.doctest
@@ -0,0 +1,44 @@
+test_fr_tva.doctest - more detailed doctests for the stdnum.fr.tva module
+
+Copyright (C) 2025 Fabien Michel
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA
+
+
+This file contains more detailed doctests for the stdnum.fr.tva module.
+
+>>> from stdnum.fr import tva
+>>> from stdnum.exceptions import *
+
+
+>>> tva.validate('Fr 40 303 265 045')
+'40303265045'
+>>> tva.validate('23 334 175 221')
+'23334175221'
+>>> tva.validate('23334175221')
+'23334175221'
+>>> tva.validate('84 323 140 391')
+Traceback (most recent call last):
+ ...
+InvalidChecksum: ...
+>>> tva.to_siren('Fr 40 303 265 045')
+'303265045'
+>>> tva.to_siren('23 334 175 221')
+'334175221'
+>>> tva.to_siren('FR 53 0000 04605') # Monaco VAT code canot be converted
+Traceback (most recent call last):
+ ...
+InvalidComponent: ...
-----------------------------------------------------------------------
Summary of changes:
stdnum/fr/rcs.py | 117 +++++++++++++++++++++
stdnum/fr/siren.py | 8 ++
stdnum/fr/tva.py | 14 +++
tests/{test_nz_ird.doctest => test_fr_rcs.doctest} | 60 +++++------
.../{test_pk_cnic.doctest => test_fr_tva.doctest} | 32 +++---
5 files changed, 181 insertions(+), 50 deletions(-)
create mode 100644 stdnum/fr/rcs.py
copy tests/{test_nz_ird.doctest => test_fr_rcs.doctest} (53%)
copy tests/{test_pk_cnic.doctest => test_fr_tva.doctest} (56%)
hooks/post-receive
--
python-stdnum
- python-stdnum branch master updated. 2.1-9-ge741318,
Commits of the python-stdnum project