From 02458a1b73ba84ed97514ca3bd1055e99a56ceb5 Mon Sep 17 00:00:00 2001 From: gabino Date: Tue, 10 Dec 2024 17:24:26 -0600 Subject: [PATCH 01/24] ci: add Codecov token to workflow configuration --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6ff81db..293a6f1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,4 +51,5 @@ jobs: flags: unittests name: codecov-umbrella fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} From fe79bec6500b6a6a8fbc7677660b77579f44724b Mon Sep 17 00:00:00 2001 From: gabino Date: Tue, 10 Dec 2024 18:00:15 -0600 Subject: [PATCH 02/24] feat: add error handling for existing bank codes and names --- clabe/errors.py | 10 ++++++++++ clabe/validations.py | 28 ++++++++++++++++++++++++++++ clabe/version.py | 2 +- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/clabe/errors.py b/clabe/errors.py index 6ecd610..4a3a396 100644 --- a/clabe/errors.py +++ b/clabe/errors.py @@ -9,3 +9,13 @@ class BankCodeValidationError(PydanticValueError): class ClabeControlDigitValidationError(PydanticValueError): code = 'clabe.control_digit' msg_template = 'clabe d铆gito de control no es v谩lido' + + +class BankCodeAlreadyExistsError(PydanticValueError): + code = 'clabe.bank_code_already_exists' + msg_template = 'c贸digo de banco ya existe' + + +class BankNameAlreadyExistsError(PydanticValueError): + code = 'clabe.bank_name_already_exists' + msg_template = 'nombre de banco ya existe' diff --git a/clabe/validations.py b/clabe/validations.py index ef25b16..d2d4cfe 100644 --- a/clabe/validations.py +++ b/clabe/validations.py @@ -2,6 +2,7 @@ from typing import List, Union from .banks import BANK_NAMES, BANKS +from .errors import BankCodeAlreadyExistsError, BankNameAlreadyExistsError CLABE_LENGTH = 18 CLABE_WEIGHTS = [3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7] @@ -61,3 +62,30 @@ def generate_new_clabes(number_of_clabes: int, prefix: str) -> List[str]: assert validate_clabe(clabe) clabes.append(clabe) return clabes + + +def configure_additional_bank( + bank_code_abm: str, bank_code_banxico: str, bank_name: str +) -> None: + """ + Configures an additional bank. + + Args: + bank_code_abm (str): The ABM code for the bank. + bank_code_banxico (str): The Banxico code for the bank. + bank_name (str): The name of the bank. + + Raises: + ValueError: If the bank_code_abm or bank_code_banxico + already exists in the provided dictionaries. + """ + + if bank_code_abm in BANKS: + raise BankCodeAlreadyExistsError + + if bank_code_banxico in BANK_NAMES: + raise BankNameAlreadyExistsError + + BANKS.update({bank_code_abm: bank_code_banxico}) + + BANK_NAMES.update({bank_code_banxico: bank_name}) diff --git a/clabe/version.py b/clabe/version.py index dee93a9..7f46aab 100644 --- a/clabe/version.py +++ b/clabe/version.py @@ -1 +1 @@ -__version__ = '1.2.16' +__version__ = '1.2.17.dev0' From 7ae5528103372e33e935907fb4440eee951ec039 Mon Sep 17 00:00:00 2001 From: gabino Date: Wed, 11 Dec 2024 09:08:18 -0600 Subject: [PATCH 03/24] ci: update GitHub Actions workflow to use new action versions --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0cda24d..84c7eba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,9 +6,9 @@ jobs: publish-pypi: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v4 - name: Set up Python 3.8 - uses: actions/setup-python@v2.2.1 + uses: actions/setup-python@v4 with: python-version: 3.8 - name: Install dependencies From e2e4cb987eb27daf4e6d914376e702ad7b59b55f Mon Sep 17 00:00:00 2001 From: gabino Date: Wed, 11 Dec 2024 09:19:43 -0600 Subject: [PATCH 04/24] chore: bump version to 1.2.17.dev1 --- clabe/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clabe/version.py b/clabe/version.py index 7f46aab..3416a74 100644 --- a/clabe/version.py +++ b/clabe/version.py @@ -1 +1 @@ -__version__ = '1.2.17.dev0' +__version__ = '1.2.17.dev1' From 2a4566e30a3c4e22acc09a3ab0d325cafc86c53f Mon Sep 17 00:00:00 2001 From: gabino Date: Wed, 11 Dec 2024 11:49:29 -0600 Subject: [PATCH 05/24] chore: update GitHub Actions workflows for release and testing --- .github/workflows/release.yml | 6 +++--- .github/workflows/test.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0cda24d..e722ac1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,9 +6,9 @@ jobs: publish-pypi: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v4 - name: Set up Python 3.8 - uses: actions/setup-python@v2.2.1 + uses: actions/setup-python@v4 with: python-version: 3.8 - name: Install dependencies @@ -17,7 +17,7 @@ jobs: run: python setup.py sdist bdist_wheel - name: Publish distribution 馃摝 to PyPI if: startsWith(github.event.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.pypi_password }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6ff81db..27058df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,4 +51,4 @@ jobs: flags: unittests name: codecov-umbrella fail_ci_if_error: true - + token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file From b356cd1b6b06e4ec2ced9cdd7eb71e386d4f2e94 Mon Sep 17 00:00:00 2001 From: gabino Date: Wed, 11 Dec 2024 12:39:28 -0600 Subject: [PATCH 06/24] fix: update PyPI token reference in GitHub Actions workflow --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e722ac1..1e04214 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,4 +20,4 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ - password: ${{ secrets.pypi_password }} + password: ${{ secrets.PYPI_TOKEN }} From 982d1317b1e24700aac4b1155a60b1e9ee34f672 Mon Sep 17 00:00:00 2001 From: gabino Date: Wed, 11 Dec 2024 12:44:33 -0600 Subject: [PATCH 07/24] fix: update PyPI token reference in release workflow to use PYPI_API_TOKEN --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1e04214..04cc895 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,4 +20,4 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ - password: ${{ secrets.PYPI_TOKEN }} + password: ${{ secrets.PYPI_API_TOKEN }} From cf757b3266910b00e7df2e77dbed90395e58ec3d Mon Sep 17 00:00:00 2001 From: gabino Date: Fri, 13 Dec 2024 11:38:34 -0600 Subject: [PATCH 08/24] refactor: rename and update error classes for bank code validation --- clabe/errors.py | 12 ++++++------ clabe/validations.py | 9 ++++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/clabe/errors.py b/clabe/errors.py index 4a3a396..02b0c83 100644 --- a/clabe/errors.py +++ b/clabe/errors.py @@ -11,11 +11,11 @@ class ClabeControlDigitValidationError(PydanticValueError): msg_template = 'clabe d铆gito de control no es v谩lido' -class BankCodeAlreadyExistsError(PydanticValueError): - code = 'clabe.bank_code_already_exists' - msg_template = 'c贸digo de banco ya existe' +class BankCodeABMAlreadyExistsError(PydanticValueError): + code = 'clabe.bank_code_abm_already_exists' + msg_template = 'c贸digo de banco ABM ya existe' -class BankNameAlreadyExistsError(PydanticValueError): - code = 'clabe.bank_name_already_exists' - msg_template = 'nombre de banco ya existe' +class BankCodeBanxicoAlreadyExistsError(PydanticValueError): + code = 'clabe.bank_code_banxico_already_exists' + msg_template = 'c贸digo de banco banxico ya existe' diff --git a/clabe/validations.py b/clabe/validations.py index d2d4cfe..54915ab 100644 --- a/clabe/validations.py +++ b/clabe/validations.py @@ -2,7 +2,10 @@ from typing import List, Union from .banks import BANK_NAMES, BANKS -from .errors import BankCodeAlreadyExistsError, BankNameAlreadyExistsError +from .errors import ( + BankCodeABMAlreadyExistsError, + BankCodeBanxicoAlreadyExistsError, +) CLABE_LENGTH = 18 CLABE_WEIGHTS = [3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7] @@ -81,10 +84,10 @@ def configure_additional_bank( """ if bank_code_abm in BANKS: - raise BankCodeAlreadyExistsError + raise BankCodeABMAlreadyExistsError if bank_code_banxico in BANK_NAMES: - raise BankNameAlreadyExistsError + raise BankCodeBanxicoAlreadyExistsError BANKS.update({bank_code_abm: bank_code_banxico}) From 04b96f105052cebea3dc2f208dcdb02e8cbd8348 Mon Sep 17 00:00:00 2001 From: gabino Date: Fri, 13 Dec 2024 11:51:32 -0600 Subject: [PATCH 09/24] feat: add configure_additional_bank function and corresponding tests --- clabe/__init__.py | 2 ++ tests/test_clabe.py | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/clabe/__init__.py b/clabe/__init__.py index c3bd33c..23a453a 100644 --- a/clabe/__init__.py +++ b/clabe/__init__.py @@ -7,12 +7,14 @@ 'generate_new_clabes', 'get_bank_name', 'validate_clabe', + 'configure_additional_bank', ] from .banks import BANK_NAMES, BANKS from .types import Clabe from .validations import ( compute_control_digit, + configure_additional_bank, generate_new_clabes, get_bank_name, validate_clabe, diff --git a/tests/test_clabe.py b/tests/test_clabe.py index 3fb9b2e..16f2650 100644 --- a/tests/test_clabe.py +++ b/tests/test_clabe.py @@ -2,10 +2,15 @@ from clabe import ( compute_control_digit, + configure_additional_bank, generate_new_clabes, get_bank_name, validate_clabe, ) +from clabe.errors import ( + BankCodeABMAlreadyExistsError, + BankCodeBanxicoAlreadyExistsError, +) VALID_CLABE = '002000000000000008' INVALID_CLABE_CONTROL_DIGIT = '002000000000000007' @@ -36,3 +41,18 @@ def test_generate_new_clabes(): for clabe in clabes: assert clabe.startswith(prefix) assert validate_clabe(clabe) + + +def test_configure_additional_bank_success(): + configure_additional_bank("777", "713", "New Bank") + assert get_bank_name('777') == 'New Bank' + + +def test_configure_additional_bank_existing_abm_code(): + with pytest.raises(BankCodeABMAlreadyExistsError): + configure_additional_bank("002", "40002", "Banamex") + + +def test_configure_additional_bank_existing_banxico_code(): + with pytest.raises(BankCodeBanxicoAlreadyExistsError): + configure_additional_bank("666", "40137", "New Bank") From b3fc82375ca03e0fc82a5040b91acae1d4cae6e0 Mon Sep 17 00:00:00 2001 From: gabino Date: Mon, 16 Dec 2024 09:56:15 -0600 Subject: [PATCH 10/24] docs: update README to include instructions for add a new bank --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 78f1051..d67c628 100644 --- a/README.md +++ b/README.md @@ -57,3 +57,10 @@ Para generar nuevo v谩lido CLABES import clabe clabe.generate_new_clabes(10, '002123456') ``` + +Para generar un nuevo banco + +```python +import clabe +clabe.configure_additional_bank('777', '713', 'New Bank') +``` From 17056cdeb7cf03afd5b7c28ad15fb4fb3cda73cf Mon Sep 17 00:00:00 2001 From: gabino Date: Mon, 16 Dec 2024 10:02:23 -0600 Subject: [PATCH 11/24] chore: bump version to 1.2.17.dev2 --- clabe/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clabe/version.py b/clabe/version.py index 3416a74..d27d6a9 100644 --- a/clabe/version.py +++ b/clabe/version.py @@ -1 +1 @@ -__version__ = '1.2.17.dev1' +__version__ = '1.2.17.dev2' From 63aa59d2c45a277c791c69548d233f1a534976f6 Mon Sep 17 00:00:00 2001 From: gabino Date: Mon, 16 Dec 2024 11:03:30 -0600 Subject: [PATCH 12/24] chore: bump version to 1.2.17 --- clabe/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clabe/version.py b/clabe/version.py index d27d6a9..d2309e3 100644 --- a/clabe/version.py +++ b/clabe/version.py @@ -1 +1 @@ -__version__ = '1.2.17.dev2' +__version__ = '1.2.17' From 8c0a10553adb64185602be807fc763630b6f5d09 Mon Sep 17 00:00:00 2001 From: gabino Date: Wed, 11 Dec 2024 11:49:29 -0600 Subject: [PATCH 13/24] chore: update GitHub Actions workflows for release and testing --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 84c7eba..e722ac1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: run: python setup.py sdist bdist_wheel - name: Publish distribution 馃摝 to PyPI if: startsWith(github.event.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.pypi_password }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 293a6f1..27058df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,5 +51,4 @@ jobs: flags: unittests name: codecov-umbrella fail_ci_if_error: true - token: ${{ secrets.CODECOV_TOKEN }} - + token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file From e7d7e47618142c739dd77fd8b1ac1b7f9672cdfe Mon Sep 17 00:00:00 2001 From: gabino Date: Wed, 11 Dec 2024 12:39:28 -0600 Subject: [PATCH 14/24] fix: update PyPI token reference in GitHub Actions workflow --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e722ac1..1e04214 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,4 +20,4 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ - password: ${{ secrets.pypi_password }} + password: ${{ secrets.PYPI_TOKEN }} From 224adf23e8fd8cfcaa0a36326149aeb5c4b71716 Mon Sep 17 00:00:00 2001 From: gabino Date: Wed, 11 Dec 2024 12:44:33 -0600 Subject: [PATCH 15/24] fix: update PyPI token reference in release workflow to use PYPI_API_TOKEN --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1e04214..04cc895 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,4 +20,4 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ - password: ${{ secrets.PYPI_TOKEN }} + password: ${{ secrets.PYPI_API_TOKEN }} From 7c035932914174f36cd897418b3a4ca1c6b7d622 Mon Sep 17 00:00:00 2001 From: gabino Date: Fri, 13 Dec 2024 11:38:34 -0600 Subject: [PATCH 16/24] refactor: rename and update error classes for bank code validation --- clabe/errors.py | 12 ++++++------ clabe/validations.py | 9 ++++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/clabe/errors.py b/clabe/errors.py index 4a3a396..02b0c83 100644 --- a/clabe/errors.py +++ b/clabe/errors.py @@ -11,11 +11,11 @@ class ClabeControlDigitValidationError(PydanticValueError): msg_template = 'clabe d铆gito de control no es v谩lido' -class BankCodeAlreadyExistsError(PydanticValueError): - code = 'clabe.bank_code_already_exists' - msg_template = 'c贸digo de banco ya existe' +class BankCodeABMAlreadyExistsError(PydanticValueError): + code = 'clabe.bank_code_abm_already_exists' + msg_template = 'c贸digo de banco ABM ya existe' -class BankNameAlreadyExistsError(PydanticValueError): - code = 'clabe.bank_name_already_exists' - msg_template = 'nombre de banco ya existe' +class BankCodeBanxicoAlreadyExistsError(PydanticValueError): + code = 'clabe.bank_code_banxico_already_exists' + msg_template = 'c贸digo de banco banxico ya existe' diff --git a/clabe/validations.py b/clabe/validations.py index d2d4cfe..54915ab 100644 --- a/clabe/validations.py +++ b/clabe/validations.py @@ -2,7 +2,10 @@ from typing import List, Union from .banks import BANK_NAMES, BANKS -from .errors import BankCodeAlreadyExistsError, BankNameAlreadyExistsError +from .errors import ( + BankCodeABMAlreadyExistsError, + BankCodeBanxicoAlreadyExistsError, +) CLABE_LENGTH = 18 CLABE_WEIGHTS = [3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7] @@ -81,10 +84,10 @@ def configure_additional_bank( """ if bank_code_abm in BANKS: - raise BankCodeAlreadyExistsError + raise BankCodeABMAlreadyExistsError if bank_code_banxico in BANK_NAMES: - raise BankNameAlreadyExistsError + raise BankCodeBanxicoAlreadyExistsError BANKS.update({bank_code_abm: bank_code_banxico}) From eeeaa7d956c675d8fdb0b5aaf9b6f8d590297f1d Mon Sep 17 00:00:00 2001 From: gabino Date: Fri, 13 Dec 2024 11:51:32 -0600 Subject: [PATCH 17/24] feat: add configure_additional_bank function and corresponding tests --- clabe/__init__.py | 2 ++ tests/test_clabe.py | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/clabe/__init__.py b/clabe/__init__.py index c3bd33c..23a453a 100644 --- a/clabe/__init__.py +++ b/clabe/__init__.py @@ -7,12 +7,14 @@ 'generate_new_clabes', 'get_bank_name', 'validate_clabe', + 'configure_additional_bank', ] from .banks import BANK_NAMES, BANKS from .types import Clabe from .validations import ( compute_control_digit, + configure_additional_bank, generate_new_clabes, get_bank_name, validate_clabe, diff --git a/tests/test_clabe.py b/tests/test_clabe.py index 3fb9b2e..16f2650 100644 --- a/tests/test_clabe.py +++ b/tests/test_clabe.py @@ -2,10 +2,15 @@ from clabe import ( compute_control_digit, + configure_additional_bank, generate_new_clabes, get_bank_name, validate_clabe, ) +from clabe.errors import ( + BankCodeABMAlreadyExistsError, + BankCodeBanxicoAlreadyExistsError, +) VALID_CLABE = '002000000000000008' INVALID_CLABE_CONTROL_DIGIT = '002000000000000007' @@ -36,3 +41,18 @@ def test_generate_new_clabes(): for clabe in clabes: assert clabe.startswith(prefix) assert validate_clabe(clabe) + + +def test_configure_additional_bank_success(): + configure_additional_bank("777", "713", "New Bank") + assert get_bank_name('777') == 'New Bank' + + +def test_configure_additional_bank_existing_abm_code(): + with pytest.raises(BankCodeABMAlreadyExistsError): + configure_additional_bank("002", "40002", "Banamex") + + +def test_configure_additional_bank_existing_banxico_code(): + with pytest.raises(BankCodeBanxicoAlreadyExistsError): + configure_additional_bank("666", "40137", "New Bank") From bab2612521009a73eab13680ac00f5266c216ce1 Mon Sep 17 00:00:00 2001 From: gabino Date: Mon, 16 Dec 2024 09:56:15 -0600 Subject: [PATCH 18/24] docs: update README to include instructions for add a new bank --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 78f1051..d67c628 100644 --- a/README.md +++ b/README.md @@ -57,3 +57,10 @@ Para generar nuevo v谩lido CLABES import clabe clabe.generate_new_clabes(10, '002123456') ``` + +Para generar un nuevo banco + +```python +import clabe +clabe.configure_additional_bank('777', '713', 'New Bank') +``` From 4bb61cf4c838b0b7e6ea8c0626227005c9465379 Mon Sep 17 00:00:00 2001 From: gabino Date: Mon, 16 Dec 2024 10:02:23 -0600 Subject: [PATCH 19/24] chore: bump version to 1.2.17.dev2 --- clabe/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clabe/version.py b/clabe/version.py index 3416a74..d27d6a9 100644 --- a/clabe/version.py +++ b/clabe/version.py @@ -1 +1 @@ -__version__ = '1.2.17.dev1' +__version__ = '1.2.17.dev2' From 247f3b493a45927a40757c5643746a5cd46d60bf Mon Sep 17 00:00:00 2001 From: gabino Date: Mon, 16 Dec 2024 11:03:30 -0600 Subject: [PATCH 20/24] chore: bump version to 1.2.17 --- clabe/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clabe/version.py b/clabe/version.py index d27d6a9..d2309e3 100644 --- a/clabe/version.py +++ b/clabe/version.py @@ -1 +1 @@ -__version__ = '1.2.17.dev2' +__version__ = '1.2.17' From 51856eddec88cb5864bc2d90573d99521ecd1a0f Mon Sep 17 00:00:00 2001 From: gabino Date: Tue, 17 Dec 2024 12:15:42 -0600 Subject: [PATCH 21/24] feat: enhance configure_additional_bank with input validation --- clabe/validations.py | 22 +++++++++++++++++++--- tests/test_clabe.py | 13 +++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/clabe/validations.py b/clabe/validations.py index 54915ab..e9de0f8 100644 --- a/clabe/validations.py +++ b/clabe/validations.py @@ -1,6 +1,8 @@ import random from typing import List, Union +from pydantic.errors import NotDigitError + from .banks import BANK_NAMES, BANKS from .errors import ( BankCodeABMAlreadyExistsError, @@ -83,12 +85,26 @@ def configure_additional_bank( already exists in the provided dictionaries. """ + if not all( + isinstance(x, str) + for x in [bank_code_abm, bank_code_banxico, bank_name] + ): + raise TypeError("All parameters must be strings") + + if not bank_code_abm.isdigit(): + raise NotDigitError + + if not bank_code_banxico.isdigit(): + raise NotDigitError + + if not bank_name.strip(): + raise ValueError("bank_name cannot be empty") + if bank_code_abm in BANKS: raise BankCodeABMAlreadyExistsError if bank_code_banxico in BANK_NAMES: raise BankCodeBanxicoAlreadyExistsError - BANKS.update({bank_code_abm: bank_code_banxico}) - - BANK_NAMES.update({bank_code_banxico: bank_name}) + BANKS[bank_code_abm] = bank_code_banxico + BANK_NAMES[bank_code_banxico] = bank_name.strip() diff --git a/tests/test_clabe.py b/tests/test_clabe.py index 16f2650..a476d45 100644 --- a/tests/test_clabe.py +++ b/tests/test_clabe.py @@ -56,3 +56,16 @@ def test_configure_additional_bank_existing_abm_code(): def test_configure_additional_bank_existing_banxico_code(): with pytest.raises(BankCodeBanxicoAlreadyExistsError): configure_additional_bank("666", "40137", "New Bank") + + +def test_configure_additional_bank_invalid_inputs(): + with pytest.raises(TypeError): + configure_additional_bank(3, 3, 3) + with pytest.raises(ValueError): + configure_additional_bank("A", "B", "C") + with pytest.raises(ValueError): + configure_additional_bank("666", "B", "C") + with pytest.raises(ValueError): + configure_additional_bank("777", "713", "") + with pytest.raises(ValueError): + configure_additional_bank("abc", "def", "Test Bank") From aeace46c7e6b95a03ea24c6b5b869380720cf278 Mon Sep 17 00:00:00 2001 From: gabino Date: Tue, 17 Dec 2024 12:54:52 -0600 Subject: [PATCH 22/24] chore: update Python version to 3.8, bump pydantic requirement to >=2.10.3, and set version to 2.0.0.dev0 --- .github/workflows/test.yml | 2 +- Makefile | 2 +- clabe/version.py | 2 +- setup.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 27058df..6a22dd3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7, 3.8] + python-version: [3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/Makefile b/Makefile index d5f48fa..7cb9232 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ SHELL := bash PATH := ./venv/bin:${PATH} -PYTHON = python3.7 +PYTHON = python3.8 PROJECT = clabe isort = isort $(PROJECT) tests setup.py black = black -S -l 79 --target-version py38 $(PROJECT) tests setup.py diff --git a/clabe/version.py b/clabe/version.py index d2309e3..8933c93 100644 --- a/clabe/version.py +++ b/clabe/version.py @@ -1 +1 @@ -__version__ = '1.2.17' +__version__ = '2.0.0.dev0' diff --git a/setup.py b/setup.py index 80d79db..fdee387 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ packages=setuptools.find_packages(), include_package_data=True, package_data=dict(clabe=['py.typed']), - install_requires=['pydantic>=1.4,<2.0'], + install_requires=['pydantic>=2.10.3'], classifiers=[ 'Programming Language :: Python :: 3', 'License :: OSI Approved :: MIT License', From b6d5a988f6736708f70ee37d2e384214c91f503e Mon Sep 17 00:00:00 2001 From: gabino Date: Tue, 17 Dec 2024 12:57:23 -0600 Subject: [PATCH 23/24] chore: upgrade Pydantic to v2 --- clabe/errors.py | 21 ----------- clabe/types.py | 82 ++++++++++++++++++++++++------------------- clabe/validations.py | 22 ++++++------ requirements-test.txt | 2 +- requirements.txt | 2 +- tests/test_clabe.py | 33 ++++++++--------- tests/test_types.py | 73 +++++++++++++++++++++++--------------- 7 files changed, 120 insertions(+), 115 deletions(-) delete mode 100644 clabe/errors.py diff --git a/clabe/errors.py b/clabe/errors.py deleted file mode 100644 index 02b0c83..0000000 --- a/clabe/errors.py +++ /dev/null @@ -1,21 +0,0 @@ -from pydantic.errors import PydanticValueError - - -class BankCodeValidationError(PydanticValueError): - code = 'clabe.bank_code' - msg_template = 'c贸digo de banco no es v谩lido' - - -class ClabeControlDigitValidationError(PydanticValueError): - code = 'clabe.control_digit' - msg_template = 'clabe d铆gito de control no es v谩lido' - - -class BankCodeABMAlreadyExistsError(PydanticValueError): - code = 'clabe.bank_code_abm_already_exists' - msg_template = 'c贸digo de banco ABM ya existe' - - -class BankCodeBanxicoAlreadyExistsError(PydanticValueError): - code = 'clabe.bank_code_banxico_already_exists' - msg_template = 'c贸digo de banco banxico ya existe' diff --git a/clabe/types.py b/clabe/types.py index 08d6052..5e3fc5f 100644 --- a/clabe/types.py +++ b/clabe/types.py @@ -1,24 +1,10 @@ -from typing import TYPE_CHECKING, ClassVar +from typing import Any, ClassVar, Dict, Type -from pydantic.errors import NotDigitError -from pydantic.validators import ( - constr_length_validator, - constr_strip_whitespace, - str_validator, -) +from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler +from pydantic_core import PydanticCustomError, core_schema -from .errors import BankCodeValidationError, ClabeControlDigitValidationError from .validations import BANK_NAMES, BANKS, compute_control_digit -if TYPE_CHECKING: - from pydantic.typing import CallableGenerator - - -def validate_digits(v: str) -> str: - if not v.isdigit(): - raise NotDigitError - return v - class Clabe(str): """ @@ -29,33 +15,55 @@ class Clabe(str): min_length: ClassVar[int] = 18 max_length: ClassVar[int] = 18 - def __init__(self, clabe: str): + def __init__(self, clabe: str) -> None: self.bank_code_abm = clabe[:3] self.bank_code_banxico = BANKS[clabe[:3]] self.bank_name = BANK_NAMES[self.bank_code_banxico] + @property + def bank_code(self) -> str: + return self.bank_code_banxico + @classmethod - def __get_validators__(cls) -> 'CallableGenerator': - yield str_validator - yield constr_strip_whitespace - yield constr_length_validator - yield validate_digits - yield cls.validate_bank_code_abm - yield cls.validate_control_digit - yield cls + def __get_pydantic_json_schema__( + cls, + schema: core_schema.CoreSchema, + handler: GetJsonSchemaHandler, + ) -> Dict[str, Any]: + json_schema = handler(schema) + json_schema.update( + type="string", + pattern="^[0-9]{18}$", + description="CLABE (Clave Bancaria Estandarizada)", + examples=["723010123456789019"], + ) + return json_schema @classmethod - def validate_bank_code_abm(cls, clabe: str) -> str: - if clabe[:3] not in BANKS.keys(): - raise BankCodeValidationError - return clabe + def __get_pydantic_core_schema__( + cls, + _: Type[Any], + __: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + return core_schema.no_info_after_validator_function( + cls._validate, + core_schema.str_schema( + min_length=cls.min_length, + max_length=cls.max_length, + strip_whitespace=cls.strip_whitespace, + ), + ) @classmethod - def validate_control_digit(cls, clabe: str) -> str: + def _validate(cls, clabe: str) -> 'Clabe': + if not clabe.isdigit(): + raise PydanticCustomError('clabe', 'debe ser num茅rico') + if clabe[:3] not in BANKS: + raise PydanticCustomError( + 'clabe.bank_code', 'c贸digo de banco no es v谩lido' + ) if clabe[-1] != compute_control_digit(clabe): - raise ClabeControlDigitValidationError - return clabe - - @property - def bank_code(self): - return self.bank_code_banxico + raise PydanticCustomError( + 'clabe.control_digit', 'clabe d铆gito de control no es v谩lido' + ) + return cls(clabe) diff --git a/clabe/validations.py b/clabe/validations.py index e9de0f8..6cc8c07 100644 --- a/clabe/validations.py +++ b/clabe/validations.py @@ -1,13 +1,9 @@ import random from typing import List, Union -from pydantic.errors import NotDigitError +from pydantic_core import PydanticCustomError from .banks import BANK_NAMES, BANKS -from .errors import ( - BankCodeABMAlreadyExistsError, - BankCodeBanxicoAlreadyExistsError, -) CLABE_LENGTH = 18 CLABE_WEIGHTS = [3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7] @@ -89,22 +85,26 @@ def configure_additional_bank( isinstance(x, str) for x in [bank_code_abm, bank_code_banxico, bank_name] ): - raise TypeError("All parameters must be strings") + raise TypeError('All parameters must be strings') if not bank_code_abm.isdigit(): - raise NotDigitError + raise TypeError('debe ser num茅rico') if not bank_code_banxico.isdigit(): - raise NotDigitError + raise TypeError('debe ser num茅rico') if not bank_name.strip(): - raise ValueError("bank_name cannot be empty") + raise ValueError('bank_name cannot be empty') if bank_code_abm in BANKS: - raise BankCodeABMAlreadyExistsError + raise PydanticCustomError( + 'clabe.bank_code_abm', 'c贸digo de banco ABM ya existe' + ) if bank_code_banxico in BANK_NAMES: - raise BankCodeBanxicoAlreadyExistsError + raise PydanticCustomError( + 'clabe.bank_code_banxico', 'c贸digo de banco banxico ya existe' + ) BANKS[bank_code_abm] = bank_code_banxico BANK_NAMES[bank_code_banxico] = bank_name.strip() diff --git a/requirements-test.txt b/requirements-test.txt index 3d06f76..a02d640 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -3,4 +3,4 @@ pytest-cov==2.11.* black==22.3.0 isort==5.10.* flake8==4.0.* -mypy==0.790 +mypy==1.13.0 diff --git a/requirements.txt b/requirements.txt index 62c77cd..e142a8a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -pydantic==1.9.0 +pydantic==2.10.3 diff --git a/tests/test_clabe.py b/tests/test_clabe.py index a476d45..a06e541 100644 --- a/tests/test_clabe.py +++ b/tests/test_clabe.py @@ -1,4 +1,5 @@ import pytest +from pydantic_core import PydanticCustomError from clabe import ( compute_control_digit, @@ -7,10 +8,6 @@ get_bank_name, validate_clabe, ) -from clabe.errors import ( - BankCodeABMAlreadyExistsError, - BankCodeBanxicoAlreadyExistsError, -) VALID_CLABE = '002000000000000008' INVALID_CLABE_CONTROL_DIGIT = '002000000000000007' @@ -44,28 +41,32 @@ def test_generate_new_clabes(): def test_configure_additional_bank_success(): - configure_additional_bank("777", "713", "New Bank") + configure_additional_bank('777', '713', 'New Bank') assert get_bank_name('777') == 'New Bank' def test_configure_additional_bank_existing_abm_code(): - with pytest.raises(BankCodeABMAlreadyExistsError): - configure_additional_bank("002", "40002", "Banamex") + with pytest.raises(PydanticCustomError) as exc_info: + configure_additional_bank('002', '40002', 'Banamex') + assert exc_info.value.type == 'clabe.bank_code_abm' + assert 'c贸digo de banco ABM ya existe' in str(exc_info.value) def test_configure_additional_bank_existing_banxico_code(): - with pytest.raises(BankCodeBanxicoAlreadyExistsError): - configure_additional_bank("666", "40137", "New Bank") + with pytest.raises(PydanticCustomError) as exc_info: + configure_additional_bank('666', '40137', 'New Bank') + assert exc_info.value.type == 'clabe.bank_code_banxico' + assert 'c贸digo de banco banxico ya existe' in str(exc_info.value) def test_configure_additional_bank_invalid_inputs(): with pytest.raises(TypeError): configure_additional_bank(3, 3, 3) + with pytest.raises(TypeError): + configure_additional_bank('A', 'B', 'C') + with pytest.raises(TypeError): + configure_additional_bank('666', 'B', 'C') with pytest.raises(ValueError): - configure_additional_bank("A", "B", "C") - with pytest.raises(ValueError): - configure_additional_bank("666", "B", "C") - with pytest.raises(ValueError): - configure_additional_bank("777", "713", "") - with pytest.raises(ValueError): - configure_additional_bank("abc", "def", "Test Bank") + configure_additional_bank('777', '713', '') + with pytest.raises(TypeError): + configure_additional_bank('abc', 'def', 'Test Bank') diff --git a/tests/test_types.py b/tests/test_types.py index 543ea23..4169b87 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1,13 +1,8 @@ import pytest -from pydantic import BaseModel -from pydantic.errors import NotDigitError +from pydantic import BaseModel, ValidationError -from clabe import BANK_NAMES, BANKS, compute_control_digit -from clabe.errors import ( - BankCodeValidationError, - ClabeControlDigitValidationError, -) -from clabe.types import Clabe, validate_digits +from clabe import BANK_NAMES, BANKS +from clabe.types import Clabe VALID_CLABE = '646180157042875763' @@ -24,23 +19,45 @@ def test_valid_clabe(): assert cuenta.clabe.bank_code == cuenta.clabe.bank_code_banxico -def test_clabe_digits(): - assert validate_digits(VALID_CLABE) - - -def test_clabe_not_digit(): - with pytest.raises(NotDigitError): - validate_digits('h' * 18) - - -def test_invalid_bank_code_abm(): - clabe = '9' * 17 - clabe += compute_control_digit(clabe) - with pytest.raises(BankCodeValidationError): - Clabe.validate_bank_code_abm(clabe) - - -def test_invalid_control_digit(): - clabe = '001' + '9' * 15 - with pytest.raises(ClabeControlDigitValidationError): - Clabe.validate_control_digit(clabe) +@pytest.mark.parametrize( + 'clabe,expected_message', + [ + pytest.param( + 'h' * 18, + 'debe ser num茅rico', + id='clabe_not_digit', + ), + pytest.param( + '9' * 17, + 'String should have at least 18 characters', + id='invalid_bank_code_abm', + ), + pytest.param( + '111180157042875763', + 'c贸digo de banco no es v谩lido', + id='invalid_bank_code', + ), + pytest.param( + '001' + '9' * 15, + 'clabe d铆gito de control no es v谩lido', + id='invalid_control_digit', + ), + ], +) +def test_invalid_clabe(clabe: Clabe, expected_message: str) -> None: + with pytest.raises(ValidationError) as exc: + Cuenta(clabe=clabe) + assert expected_message in str(exc.value) + +def test_get_json_schema() -> None: + from pydantic import TypeAdapter + adapter = TypeAdapter(Clabe) + schema = adapter.json_schema() + assert schema == { + 'description': 'CLABE (Clave Bancaria Estandarizada)', + 'examples': ['723010123456789019'], + 'maxLength': 18, + 'minLength': 18, + 'pattern': '^[0-9]{18}$', + 'type': 'string', + } \ No newline at end of file From 007ee9f63c25f44a54b3cce873177c6e2a2c47c2 Mon Sep 17 00:00:00 2001 From: gabino Date: Tue, 17 Dec 2024 13:01:38 -0600 Subject: [PATCH 24/24] docs: update Python version requirement in README --- README.md | 2 +- tests/test_types.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d67c628..f7a33f1 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ https://es.wikipedia.org/wiki/CLABE ## Requerimientos -Python 3.6 o superior. +Python 3.8 o superior. ## Instalaci贸n diff --git a/tests/test_types.py b/tests/test_types.py index 4169b87..a23a358 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -49,8 +49,10 @@ def test_invalid_clabe(clabe: Clabe, expected_message: str) -> None: Cuenta(clabe=clabe) assert expected_message in str(exc.value) + def test_get_json_schema() -> None: from pydantic import TypeAdapter + adapter = TypeAdapter(Clabe) schema = adapter.json_schema() assert schema == { @@ -60,4 +62,4 @@ def test_get_json_schema() -> None: 'minLength': 18, 'pattern': '^[0-9]{18}$', 'type': 'string', - } \ No newline at end of file + }