cuenca-validations 2.1.28__tar.gz → 2.1.29.dev0__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.
Files changed (36) hide show
  1. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/PKG-INFO +1 -1
  2. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/types/general.py +8 -1
  3. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/types/queries.py +5 -0
  4. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/validators.py +14 -0
  5. cuenca_validations-2.1.29.dev0/cuenca_validations/version.py +1 -0
  6. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations.egg-info/PKG-INFO +1 -1
  7. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/tests/test_types.py +46 -0
  8. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/tests/test_validators.py +17 -0
  9. cuenca_validations-2.1.28/cuenca_validations/version.py +0 -1
  10. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/LICENSE +0 -0
  11. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/README.md +0 -0
  12. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/__init__.py +0 -0
  13. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/card_bins.py +0 -0
  14. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/errors.py +0 -0
  15. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/py.typed +0 -0
  16. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/types/__init__.py +0 -0
  17. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/types/card.py +0 -0
  18. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/types/enums.py +0 -0
  19. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/types/files.py +0 -0
  20. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/types/helpers.py +0 -0
  21. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/types/identities.py +0 -0
  22. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/types/morals.py +0 -0
  23. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/types/requests.py +0 -0
  24. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations/typing.py +0 -0
  25. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations.egg-info/SOURCES.txt +0 -0
  26. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations.egg-info/dependency_links.txt +0 -0
  27. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations.egg-info/requires.txt +0 -0
  28. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/cuenca_validations.egg-info/top_level.txt +0 -0
  29. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/setup.cfg +0 -0
  30. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/setup.py +0 -0
  31. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/tests/__init__.py +0 -0
  32. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/tests/test_card.py +0 -0
  33. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/tests/test_errors.py +0 -0
  34. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/tests/test_helpers.py +0 -0
  35. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/tests/test_requests.py +0 -0
  36. {cuenca_validations-2.1.28 → cuenca_validations-2.1.29.dev0}/tests/test_statement.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuenca_validations
3
- Version: 2.1.28
3
+ Version: 2.1.29.dev0
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -3,6 +3,7 @@ from dataclasses import dataclass
3
3
  from typing import Annotated, Any, Optional
4
4
 
5
5
  from pydantic import (
6
+ AfterValidator,
6
7
  AnyUrl,
7
8
  Field,
8
9
  HttpUrl,
@@ -11,7 +12,7 @@ from pydantic import (
11
12
  StringConstraints,
12
13
  )
13
14
 
14
- from ..validators import sanitize_dict, sanitize_item
15
+ from ..validators import normalize_name, sanitize_dict, sanitize_item
15
16
  from .enums import (
16
17
  AccountUseType,
17
18
  IncomeType,
@@ -33,6 +34,12 @@ NonEmptyStr = Annotated[
33
34
  str, StringConstraints(strip_whitespace=True, min_length=1)
34
35
  ]
35
36
 
37
+ NormalizedName = Annotated[
38
+ str,
39
+ StringConstraints(strip_whitespace=True, min_length=2),
40
+ AfterValidator(normalize_name),
41
+ ]
42
+
36
43
 
37
44
  class SantizedDict(dict):
38
45
  def __init__(self, *args, **kwargs):
@@ -1,6 +1,7 @@
1
1
  import datetime as dt
2
2
  from typing import Annotated, Optional
3
3
 
4
+ from clabe import Clabe
4
5
  from pydantic import (
5
6
  BaseModel,
6
7
  ConfigDict,
@@ -26,6 +27,7 @@ from .enums import (
26
27
  TransferNetwork,
27
28
  UserStatus,
28
29
  )
30
+ from .general import NormalizedName
29
31
  from .identities import Curp
30
32
 
31
33
  MAX_PAGE_SIZE = 100
@@ -157,6 +159,9 @@ class UserQuery(QueryParams):
157
159
  status: Optional[UserStatus] = None
158
160
  identity_uri: Optional[str] = None
159
161
  has_curp_document: Optional[bool] = None
162
+ clabe: Optional[Clabe] = None
163
+ curp: Optional[Curp] = None
164
+ name: Optional[NormalizedName] = None
160
165
 
161
166
 
162
167
  class IdentityQuery(QueryParams):
@@ -1,6 +1,7 @@
1
1
  import base64
2
2
  import datetime as dt
3
3
  import re
4
+ import unicodedata
4
5
  from enum import Enum
5
6
  from typing import Any, Callable, Optional, Union
6
7
 
@@ -34,6 +35,19 @@ def normalize_phone_number(phone_number: str) -> str:
34
35
  return f'+{pn}'
35
36
 
36
37
 
38
+ def normalize_name(name: str) -> str:
39
+ """Normalize names for search/index matching.
40
+
41
+ Strips accents, lowercases, and collapses internal whitespace.
42
+
43
+ Raúl Andrés -> raul andres
44
+ MARÍA JOSÉ -> maria jose
45
+ """
46
+ collapsed = ' '.join(name.split())
47
+ nfkd = unicodedata.normalize('NFKD', collapsed)
48
+ return ''.join(c for c in nfkd if not unicodedata.combining(c)).lower()
49
+
50
+
37
51
  def sanitize_dict(d: dict) -> dict:
38
52
  for k, v in d.items():
39
53
  d[k] = sanitize_item(v)
@@ -0,0 +1 @@
1
+ __version__ = '2.1.29.dev0'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuenca_validations
3
- Version: 2.1.28
3
+ Version: 2.1.29.dev0
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -5,6 +5,7 @@ from enum import Enum
5
5
  from typing import Annotated
6
6
 
7
7
  import pytest
8
+ from clabe import Clabe
8
9
  from freezegun import freeze_time
9
10
  from pydantic import AfterValidator, BaseModel, SecretStr, ValidationError
10
11
  from pydantic.fields import FieldInfo
@@ -16,6 +17,7 @@ from cuenca_validations.types import (
16
17
  SantizedDict,
17
18
  SessionRequest,
18
19
  TransactionStatus,
20
+ UserQuery,
19
21
  digits,
20
22
  get_account_use_type_name,
21
23
  get_income_type_name,
@@ -201,6 +203,50 @@ def test_card_query_exp_cvv_if_number_not_set(input_value):
201
203
  CardQuery(**input_value)
202
204
 
203
205
 
206
+ def test_user_query_accepts_new_fields():
207
+ query = UserQuery(
208
+ clabe='646180157098510917',
209
+ curp='ABCD920604HDFSRN03',
210
+ name='Pedro Páramo',
211
+ )
212
+ assert isinstance(query.clabe, Clabe)
213
+ assert query.clabe == '646180157098510917'
214
+ assert query.curp == 'ABCD920604HDFSRN03'
215
+ assert query.name == 'pedro paramo'
216
+
217
+
218
+ @pytest.mark.parametrize(
219
+ 'raw, normalized',
220
+ [
221
+ ('ab', 'ab'),
222
+ (' ab ', 'ab'),
223
+ ('Raúl Andrés', 'raul andres'),
224
+ ('raul Andres', 'raul andres'),
225
+ (' RAÚL ANDRÉS ', 'raul andres'),
226
+ ('María José', 'maria jose'),
227
+ ('ÑANDÚ', 'nandu'),
228
+ ],
229
+ )
230
+ def test_user_query_name_normalizes(raw, normalized):
231
+ assert UserQuery(name=raw).name == normalized
232
+
233
+
234
+ @pytest.mark.parametrize(
235
+ 'field, value',
236
+ [
237
+ ('clabe', 'not-a-clabe'),
238
+ ('curp', 'not-a-curp'),
239
+ ('name', ''),
240
+ ('name', ' '),
241
+ ('name', 'a'),
242
+ ('name', ' a '),
243
+ ],
244
+ )
245
+ def test_user_query_rejects_invalid(field, value):
246
+ with pytest.raises(ValidationError):
247
+ UserQuery(**{field: value})
248
+
249
+
204
250
  def test_exclude_none_in_dict():
205
251
  request = ApiKeyUpdateRequest(user_id='US123')
206
252
  assert request.model_dump() == dict(user_id='US123')
@@ -2,6 +2,7 @@ import pytest
2
2
 
3
3
  from cuenca_validations.validators import (
4
4
  normalize_email,
5
+ normalize_name,
5
6
  normalize_phone_number,
6
7
  )
7
8
 
@@ -33,3 +34,19 @@ def test_normalize_email(raw: str, normalized: str) -> None:
33
34
  )
34
35
  def test_normalize_phone_number(raw: str, normalized: str) -> None:
35
36
  assert normalize_phone_number(raw) == normalized
37
+
38
+
39
+ @pytest.mark.parametrize(
40
+ 'raw, normalized',
41
+ [
42
+ ('Raúl Andrés', 'raul andres'), # accents + mixed case
43
+ ('raul andres', 'raul andres'), # already normalized
44
+ ('RAÚL ANDRÉS', 'raul andres'), # uppercase with accents
45
+ ('ÑANDÚ', 'nandu'), # ñ and accent
46
+ ('María José', 'maria jose'), # collapse internal whitespace
47
+ (' Raúl ', 'raul'), # trim + lowercase
48
+ ('Nuño Garçía', 'nuno garcia'), # tilde and cedilla
49
+ ],
50
+ )
51
+ def test_normalize_name(raw: str, normalized: str) -> None:
52
+ assert normalize_name(raw) == normalized
@@ -1 +0,0 @@
1
- __version__ = '2.1.28'