|
1 | | -from typing import TYPE_CHECKING, ClassVar |
| 1 | +from typing import Any, Dict, Type |
2 | 2 |
|
3 | | -from pydantic.v1.errors import NotDigitError |
4 | | -from pydantic.v1.validators import ( |
5 | | - constr_length_validator, |
6 | | - constr_strip_whitespace, |
7 | | - str_validator, |
8 | | -) |
| 3 | +from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler |
| 4 | +from pydantic_core import PydanticCustomError, core_schema |
9 | 5 |
|
10 | | -from .errors import BankCodeValidationError, ClabeControlDigitValidationError |
11 | 6 | from .validations import BANK_NAMES, BANKS, compute_control_digit |
12 | 7 |
|
13 | | -if TYPE_CHECKING: |
14 | | - from pydantic.v1.typing import CallableGenerator |
15 | | - |
16 | | - |
17 | | -def validate_digits(v: str) -> str: |
18 | | - if not v.isdigit(): |
19 | | - raise NotDigitError |
20 | | - return v |
| 8 | +CLABE_LENGTH = 18 |
21 | 9 |
|
22 | 10 |
|
23 | 11 | class Clabe(str): |
24 | 12 | """ |
25 | 13 | Based on: https://es.wikipedia.org/wiki/CLABE |
26 | 14 | """ |
27 | 15 |
|
28 | | - strip_whitespace: ClassVar[bool] = True |
29 | | - min_length: ClassVar[int] = 18 |
30 | | - max_length: ClassVar[int] = 18 |
31 | | - |
32 | | - def __init__(self, clabe: str): |
| 16 | + def __init__(self, clabe: str) -> None: |
33 | 17 | self.bank_code_abm = clabe[:3] |
34 | 18 | self.bank_code_banxico = BANKS[clabe[:3]] |
35 | 19 | self.bank_name = BANK_NAMES[self.bank_code_banxico] |
36 | 20 |
|
| 21 | + @property |
| 22 | + def bank_code(self) -> str: |
| 23 | + return self.bank_code_banxico |
| 24 | + |
37 | 25 | @classmethod |
38 | | - def __get_validators__(cls) -> 'CallableGenerator': |
39 | | - yield str_validator |
40 | | - yield constr_strip_whitespace |
41 | | - yield constr_length_validator |
42 | | - yield validate_digits |
43 | | - yield cls.validate_bank_code_abm |
44 | | - yield cls.validate_control_digit |
45 | | - yield cls |
| 26 | + def __get_pydantic_json_schema__( |
| 27 | + cls, |
| 28 | + schema: core_schema.CoreSchema, |
| 29 | + handler: GetJsonSchemaHandler, |
| 30 | + ) -> Dict[str, Any]: |
| 31 | + json_schema = handler(schema) |
| 32 | + json_schema.update( |
| 33 | + type="string", |
| 34 | + pattern="^[0-9]{18}$", |
| 35 | + description="CLABE (Clave Bancaria Estandarizada)", |
| 36 | + examples=["723010123456789019"], |
| 37 | + ) |
| 38 | + return json_schema |
46 | 39 |
|
47 | 40 | @classmethod |
48 | | - def validate_bank_code_abm(cls, clabe: str) -> str: |
49 | | - if clabe[:3] not in BANKS.keys(): |
50 | | - raise BankCodeValidationError |
51 | | - return clabe |
| 41 | + def __get_pydantic_core_schema__( |
| 42 | + cls, |
| 43 | + _: Type[Any], |
| 44 | + __: GetCoreSchemaHandler, |
| 45 | + ) -> core_schema.CoreSchema: |
| 46 | + return core_schema.no_info_after_validator_function( |
| 47 | + cls._validate, |
| 48 | + core_schema.str_schema( |
| 49 | + min_length=CLABE_LENGTH, |
| 50 | + max_length=CLABE_LENGTH, |
| 51 | + strip_whitespace=True, |
| 52 | + ), |
| 53 | + ) |
52 | 54 |
|
53 | 55 | @classmethod |
54 | | - def validate_control_digit(cls, clabe: str) -> str: |
| 56 | + def _validate(cls, clabe: str) -> 'Clabe': |
| 57 | + if not clabe.isdigit(): |
| 58 | + raise PydanticCustomError('clabe', 'debe ser numérico') |
| 59 | + if clabe[:3] not in BANKS: |
| 60 | + raise PydanticCustomError( |
| 61 | + 'clabe.bank_code', 'código de banco no es válido' |
| 62 | + ) |
55 | 63 | if clabe[-1] != compute_control_digit(clabe): |
56 | | - raise ClabeControlDigitValidationError |
57 | | - return clabe |
58 | | - |
59 | | - @property |
60 | | - def bank_code(self): |
61 | | - return self.bank_code_banxico |
| 64 | + raise PydanticCustomError( |
| 65 | + 'clabe.control_digit', 'clabe dígito de control no es válido' |
| 66 | + ) |
| 67 | + return cls(clabe) |
0 commit comments