cuenca 1.0.3.dev1__tar.gz → 2.0.0.dev2__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 (112) hide show
  1. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/PKG-INFO +10 -6
  2. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/exc.py +4 -5
  3. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/api_keys.py +11 -9
  4. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/arpc.py +6 -5
  5. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/balance_entries.py +2 -4
  6. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/base.py +52 -41
  7. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/card_activations.py +4 -2
  8. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/card_transactions.py +4 -1
  9. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/card_validations.py +7 -7
  10. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/cards.py +7 -6
  11. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/clabes.py +2 -2
  12. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/curp_validations.py +46 -42
  13. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/deposits.py +1 -1
  14. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/endpoints.py +25 -27
  15. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/file_batches.py +12 -4
  16. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/files.py +15 -4
  17. cuenca-2.0.0.dev2/cuenca/resources/identities.py +39 -0
  18. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/kyc_validations.py +11 -8
  19. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/kyc_verifications.py +10 -9
  20. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/limited_wallets.py +4 -4
  21. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/login_tokens.py +7 -5
  22. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/otps.py +5 -3
  23. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/platforms.py +30 -31
  24. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/questionnaires.py +8 -5
  25. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/resources.py +2 -2
  26. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/savings.py +5 -5
  27. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/sessions.py +11 -11
  28. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/transfers.py +5 -4
  29. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/user_credentials.py +8 -3
  30. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/user_events.py +5 -3
  31. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/user_lists_validation.py +7 -3
  32. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/user_logins.py +7 -6
  33. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/users.py +49 -51
  34. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/verifications.py +17 -11
  35. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/wallet_transactions.py +1 -1
  36. cuenca-2.0.0.dev2/cuenca/resources/webhooks.py +17 -0
  37. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/whatsapp_transfers.py +4 -4
  38. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/version.py +1 -1
  39. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca.egg-info/PKG-INFO +10 -6
  40. cuenca-2.0.0.dev2/cuenca.egg-info/requires.txt +3 -0
  41. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/setup.py +9 -5
  42. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_api_keys.py +1 -1
  43. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_endpoints.py +1 -1
  44. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_sessions.py +2 -2
  45. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_transfers.py +1 -1
  46. cuenca-1.0.3.dev1/cuenca/resources/identities.py +0 -39
  47. cuenca-1.0.3.dev1/cuenca/resources/webhooks.py +0 -18
  48. cuenca-1.0.3.dev1/cuenca.egg-info/requires.txt +0 -5
  49. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/LICENSE +0 -0
  50. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/README.md +0 -0
  51. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/__init__.py +0 -0
  52. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/http/__init__.py +0 -0
  53. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/http/client.py +0 -0
  54. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/jwt.py +0 -0
  55. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/py.typed +0 -0
  56. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/__init__.py +0 -0
  57. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/accounts.py +0 -0
  58. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/bill_payments.py +0 -0
  59. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/cash_references.py +0 -0
  60. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/commissions.py +0 -0
  61. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/identity_events.py +0 -0
  62. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/service_providers.py +0 -0
  63. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca/resources/statements.py +0 -0
  64. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca.egg-info/SOURCES.txt +0 -0
  65. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca.egg-info/dependency_links.txt +0 -0
  66. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/cuenca.egg-info/top_level.txt +0 -0
  67. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/setup.cfg +0 -0
  68. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/__init__.py +0 -0
  69. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/conftest.py +0 -0
  70. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/http/__init__.py +0 -0
  71. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/http/conftest.py +0 -0
  72. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/http/test_client.py +0 -0
  73. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/__init__.py +0 -0
  74. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_accounts.py +0 -0
  75. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_arpc.py +0 -0
  76. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_balance_entries.py +0 -0
  77. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_bill_payments.py +0 -0
  78. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_card_activations.py +0 -0
  79. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_card_transactions.py +0 -0
  80. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_card_validations.py +0 -0
  81. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_cards.py +0 -0
  82. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_cash_references.py +0 -0
  83. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_clabes.py +0 -0
  84. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_commissions.py +0 -0
  85. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_curp_validations.py +0 -0
  86. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_deposits.py +0 -0
  87. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_file_batches.py +0 -0
  88. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_files.py +0 -0
  89. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_identities.py +0 -0
  90. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_identity_events.py +0 -0
  91. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_kyc_validations.py +0 -0
  92. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_kyc_verifications.py +0 -0
  93. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_limited_wallets.py +0 -0
  94. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_login_tokens.py +0 -0
  95. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_otps.py +0 -0
  96. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_platforms.py +0 -0
  97. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_questionnaires.py +0 -0
  98. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_resources.py +0 -0
  99. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_savings.py +0 -0
  100. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_service_providers.py +0 -0
  101. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_statements.py +0 -0
  102. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_user_credentials.py +0 -0
  103. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_user_events.py +0 -0
  104. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_user_lists_validation.py +0 -0
  105. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_user_logins.py +0 -0
  106. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_users.py +0 -0
  107. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_verifications.py +0 -0
  108. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_wallet_transactions.py +0 -0
  109. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_webhooks.py +0 -0
  110. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/resources/test_whatsapp_transfers.py +0 -0
  111. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/test_cuenca.py +0 -0
  112. {cuenca-1.0.3.dev1 → cuenca-2.0.0.dev2}/tests/test_jwt.py +0 -0
@@ -1,19 +1,23 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cuenca
3
- Version: 1.0.3.dev1
3
+ Version: 2.0.0.dev2
4
4
  Summary: Cuenca API Client
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-python
6
6
  Author: Cuenca
7
7
  Author-email: dev@cuenca.com
8
- Classifier: Programming Language :: Python :: 3.8
8
+ Classifier: Programming Language :: Python :: 3.9
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
9
13
  Classifier: License :: OSI Approved :: MIT License
10
14
  Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.8
15
+ Requires-Python: >=3.9
12
16
  Description-Content-Type: text/markdown
13
17
  License-File: LICENSE
14
- Requires-Dist: requests<28,>=2.24
15
- Requires-Dist: dataclasses>=0.7; python_version < "3.8"
16
- Requires-Dist: cuenca-validations<0.12.0,>=0.11.3
18
+ Requires-Dist: requests>=2.32.3
19
+ Requires-Dist: cuenca-validations==2.0.0.dev8
20
+ Requires-Dist: pydantic-extra-types>=2.10.1
17
21
 
18
22
  # Cuenca – Python client library
19
23
 
@@ -1,5 +1,3 @@
1
- from dataclasses import dataclass
2
-
3
1
  from cuenca_validations.typing import DictStrAny
4
2
 
5
3
 
@@ -19,10 +17,11 @@ class MultipleResultsFound(CuencaException):
19
17
  """One result was expected but multiple were returned"""
20
18
 
21
19
 
22
- @dataclass
23
20
  class CuencaResponseException(CuencaException):
24
- json: DictStrAny
25
- status_code: int
21
+ def __init__(self, json: DictStrAny, status_code: int) -> None:
22
+ self.json = json
23
+ self.status_code = status_code
24
+ super().__init__()
26
25
 
27
26
  def __str__(self) -> str:
28
27
  return repr(self)
@@ -1,7 +1,8 @@
1
1
  import datetime as dt
2
- from typing import ClassVar, Optional
2
+ from typing import ClassVar, Optional, cast
3
3
 
4
4
  from cuenca_validations.types import ApiKeyQuery, ApiKeyUpdateRequest
5
+ from pydantic import ConfigDict
5
6
 
6
7
  from ..http import Session, session as global_session
7
8
  from .base import Creatable, Queryable, Retrievable, Updateable
@@ -12,11 +13,10 @@ class ApiKey(Creatable, Queryable, Retrievable, Updateable):
12
13
  _query_params: ClassVar = ApiKeyQuery
13
14
 
14
15
  secret: str
15
- deactivated_at: Optional[dt.datetime]
16
- user_id: Optional[str]
17
-
18
- class Config:
19
- schema_extra = {
16
+ deactivated_at: Optional[dt.datetime] = None
17
+ user_id: Optional[str] = None
18
+ model_config = ConfigDict(
19
+ json_schema_extra={
20
20
  'example': {
21
21
  'id': 'AKNEUInh69SuKXXmK95sROwQ',
22
22
  'updated_at': '2021-08-24T14:15:22Z',
@@ -26,6 +26,7 @@ class ApiKey(Creatable, Queryable, Retrievable, Updateable):
26
26
  'user_id': 'USWqY5cvkISJOxHyEKjAKf8w',
27
27
  }
28
28
  }
29
+ )
29
30
 
30
31
  @property
31
32
  def active(self) -> bool:
@@ -36,7 +37,7 @@ class ApiKey(Creatable, Queryable, Retrievable, Updateable):
36
37
 
37
38
  @classmethod
38
39
  def create(cls, *, session: Session = global_session) -> 'ApiKey':
39
- return cls._create(session=session)
40
+ return cast('ApiKey', cls._create(session=session))
40
41
 
41
42
  @classmethod
42
43
  def deactivate(
@@ -55,7 +56,7 @@ class ApiKey(Creatable, Queryable, Retrievable, Updateable):
55
56
  """
56
57
  url = cls._resource + f'/{api_key_id}'
57
58
  resp = session.delete(url, dict(minutes=minutes))
58
- return cls(**resp)
59
+ return cast('ApiKey', cls._from_dict(resp))
59
60
 
60
61
  @classmethod
61
62
  def update(
@@ -74,4 +75,5 @@ class ApiKey(Creatable, Queryable, Retrievable, Updateable):
74
75
  req = ApiKeyUpdateRequest(
75
76
  metadata=metadata, user_id=user_id, platform_id=platform_id
76
77
  )
77
- return cls._update(api_key_id, **req.dict(), session=session)
78
+ resp = cls._update(api_key_id, **req.dict(), session=session)
79
+ return cast('ApiKey', resp)
@@ -1,6 +1,7 @@
1
1
  import datetime as dt
2
- from typing import ClassVar, Optional
2
+ from typing import ClassVar, Optional, cast
3
3
 
4
+ from cuenca_validations.types.enums import TrackDataMethod
4
5
  from cuenca_validations.types.requests import ARPCRequest
5
6
 
6
7
  from ..http import Session, session as global_session
@@ -23,8 +24,8 @@ class Arpc(Creatable):
23
24
 
24
25
  created_at: dt.datetime
25
26
  card_uri: str
26
- is_valid_arqc: Optional[bool]
27
- arpc: Optional[str]
27
+ is_valid_arqc: Optional[bool] = None
28
+ arpc: Optional[str] = None
28
29
 
29
30
  @classmethod
30
31
  def create(
@@ -50,6 +51,6 @@ class Arpc(Creatable):
50
51
  transaction_counter=transaction_counter,
51
52
  pan_sequence=pan_sequence,
52
53
  unique_number=unique_number,
53
- track_data_method=track_data_method,
54
+ track_data_method=cast(TrackDataMethod, track_data_method),
54
55
  )
55
- return cls._create(session=session, **req.dict())
56
+ return cast('Arpc', cls._create(session=session, **req.model_dump()))
@@ -1,4 +1,4 @@
1
- from typing import ClassVar, TypeVar, cast
1
+ from typing import ClassVar, Union, cast
2
2
 
3
3
  from cuenca_validations.types import BalanceEntryQuery, EntryType
4
4
 
@@ -8,9 +8,7 @@ from .cards import Card
8
8
  from .resources import retrieve_uri
9
9
  from .service_providers import ServiceProvider
10
10
 
11
- FundingInstrument = TypeVar(
12
- 'FundingInstrument', Account, ServiceProvider, Card
13
- )
11
+ FundingInstrument = Union[Account, ServiceProvider, Card]
14
12
 
15
13
 
16
14
  class BalanceEntry(Retrievable, Queryable):
@@ -2,7 +2,7 @@ import base64
2
2
  import datetime as dt
3
3
  import json
4
4
  from io import BytesIO
5
- from typing import ClassVar, Generator, Optional, Type, TypeVar, cast
5
+ from typing import Any, ClassVar, Dict, Generator, Optional
6
6
  from urllib.parse import urlencode
7
7
 
8
8
  from cuenca_validations.types import (
@@ -12,35 +12,48 @@ from cuenca_validations.types import (
12
12
  TransactionQuery,
13
13
  TransactionStatus,
14
14
  )
15
- from pydantic import BaseModel, Extra
15
+ from pydantic import BaseModel
16
16
 
17
17
  from ..exc import MultipleResultsFound, NoResultFound
18
18
  from ..http import Session, session as global_session
19
19
 
20
- R_co = TypeVar('R_co', bound='Resource', covariant=True)
21
-
22
20
 
23
21
  class Resource(BaseModel):
24
22
  _resource: ClassVar[str]
25
23
 
26
24
  id: str
27
25
 
28
- class Config:
29
- extra = Extra.ignore
26
+ @classmethod
27
+ def _from_dict(cls, obj_dict: Dict[str, Any]) -> 'Resource':
28
+ cls._filter_excess_fields(obj_dict)
29
+ return cls(**obj_dict)
30
+
31
+ @classmethod
32
+ def _filter_excess_fields(cls, obj_dict):
33
+ """
34
+ dataclasses don't allow __init__ to be called with excess fields. This
35
+ method allows the API to add fields in the response body without
36
+ breaking the client
37
+ """
38
+ excess = set(obj_dict.keys()) - set(
39
+ cls.schema().get("properties").keys()
40
+ )
41
+ for f in excess:
42
+ del obj_dict[f]
30
43
 
31
44
  def to_dict(self):
32
- return SantizedDict(self.dict())
45
+ return SantizedDict(self.model_dump())
33
46
 
34
47
 
35
48
  class Retrievable(Resource):
36
49
  @classmethod
37
50
  def retrieve(
38
- cls: Type[R_co], id: str, *, session: Session = global_session
39
- ) -> R_co:
51
+ cls, id: str, *, session: Session = global_session
52
+ ) -> Resource:
40
53
  resp = session.get(f'/{cls._resource}/{id}')
41
- return cls(**resp)
54
+ return cls._from_dict(resp)
42
55
 
43
- def refresh(self, *, session: Session = global_session) -> None:
56
+ def refresh(self, *, session: Session = global_session):
44
57
  new = self.retrieve(self.id, session=session)
45
58
  for attr, value in new.__dict__.items():
46
59
  setattr(self, attr, value)
@@ -48,11 +61,9 @@ class Retrievable(Resource):
48
61
 
49
62
  class Creatable(Resource):
50
63
  @classmethod
51
- def _create(
52
- cls: Type[R_co], *, session: Session = global_session, **data
53
- ) -> R_co:
64
+ def _create(cls, *, session: Session = global_session, **data) -> Resource:
54
65
  resp = session.post(cls._resource, data)
55
- return cls(**resp)
66
+ return cls._from_dict(resp)
56
67
 
57
68
 
58
69
  class Updateable(Resource):
@@ -61,31 +72,31 @@ class Updateable(Resource):
61
72
 
62
73
  @classmethod
63
74
  def _update(
64
- cls: Type[R_co], id: str, *, session: Session = global_session, **data
65
- ) -> R_co:
75
+ cls, id: str, *, session: Session = global_session, **data
76
+ ) -> Resource:
66
77
  resp = session.patch(f'/{cls._resource}/{id}', data)
67
- return cls(**resp)
78
+ return cls._from_dict(resp)
68
79
 
69
80
 
70
81
  class Deactivable(Resource):
71
- deactivated_at: Optional[dt.datetime]
82
+ deactivated_at: Optional[dt.datetime] = None
72
83
 
73
84
  @classmethod
74
85
  def deactivate(
75
- cls: Type[R_co], id: str, *, session: Session = global_session, **data
76
- ) -> R_co:
86
+ cls, id: str, *, session: Session = global_session, **data
87
+ ) -> Resource:
77
88
  resp = session.delete(f'/{cls._resource}/{id}', data)
78
- return cls(**resp)
89
+ return cls._from_dict(resp)
79
90
 
80
91
  @property
81
- def is_active(self) -> bool:
92
+ def is_active(self):
82
93
  return not self.deactivated_at
83
94
 
84
95
 
85
96
  class Downloadable(Resource):
86
97
  @classmethod
87
98
  def download(
88
- cls: Type[R_co],
99
+ cls,
89
100
  id: str,
90
101
  file_format: FileFormat = FileFormat.any,
91
102
  *,
@@ -110,13 +121,13 @@ class Downloadable(Resource):
110
121
  class Uploadable(Resource):
111
122
  @classmethod
112
123
  def _upload(
113
- cls: Type[R_co],
124
+ cls,
114
125
  file: bytes,
115
126
  user_id: str,
116
127
  *,
117
128
  session: Session = global_session,
118
129
  **data,
119
- ) -> R_co:
130
+ ) -> Resource:
120
131
  encoded_file = base64.b64encode(file)
121
132
  resp = session.request(
122
133
  'post',
@@ -127,7 +138,7 @@ class Uploadable(Resource):
127
138
  **{k: (None, v) for k, v in data.items()},
128
139
  ),
129
140
  )
130
- return cls(**json.loads(resp))
141
+ return cls._from_dict(json.loads(resp))
131
142
 
132
143
 
133
144
  class Queryable(Resource):
@@ -137,9 +148,9 @@ class Queryable(Resource):
137
148
 
138
149
  @classmethod
139
150
  def one(
140
- cls: Type[R_co], *, session: Session = global_session, **query_params
141
- ) -> R_co:
142
- q = cast(Queryable, cls)._query_params(limit=2, **query_params)
151
+ cls, *, session: Session = global_session, **query_params
152
+ ) -> Resource:
153
+ q = cls._query_params(limit=2, **query_params)
143
154
  resp = session.get(cls._resource, q.dict())
144
155
  items = resp['items']
145
156
  len_items = len(items)
@@ -147,40 +158,40 @@ class Queryable(Resource):
147
158
  raise NoResultFound
148
159
  if len_items > 1:
149
160
  raise MultipleResultsFound
150
- return cls(**items[0])
161
+ return cls._from_dict(items[0])
151
162
 
152
163
  @classmethod
153
164
  def first(
154
- cls: Type[R_co], *, session: Session = global_session, **query_params
155
- ) -> Optional[R_co]:
156
- q = cast(Queryable, cls)._query_params(limit=1, **query_params)
165
+ cls, *, session: Session = global_session, **query_params
166
+ ) -> Optional[Resource]:
167
+ q = cls._query_params(limit=1, **query_params)
157
168
  resp = session.get(cls._resource, q.dict())
158
169
  try:
159
170
  item = resp['items'][0]
160
171
  except IndexError:
161
172
  rv = None
162
173
  else:
163
- rv = cls(**item)
174
+ rv = cls._from_dict(item)
164
175
  return rv
165
176
 
166
177
  @classmethod
167
178
  def count(
168
- cls: Type[R_co], *, session: Session = global_session, **query_params
179
+ cls, *, session: Session = global_session, **query_params
169
180
  ) -> int:
170
- q = cast(Queryable, cls)._query_params(count=True, **query_params)
181
+ q = cls._query_params(count=True, **query_params)
171
182
  resp = session.get(cls._resource, q.dict())
172
183
  return resp['count']
173
184
 
174
185
  @classmethod
175
186
  def all(
176
- cls: Type[R_co], *, session: Session = global_session, **query_params
177
- ) -> Generator[R_co, None, None]:
187
+ cls, *, session: Session = global_session, **query_params
188
+ ) -> Generator[Resource, None, None]:
178
189
  session = session or global_session
179
- q = cast(Queryable, cls)._query_params(**query_params)
190
+ q = cls._query_params(**query_params)
180
191
  next_page_uri = f'{cls._resource}?{urlencode(q.dict())}'
181
192
  while next_page_uri:
182
193
  page = session.get(next_page_uri)
183
- yield from (cls(**item) for item in page['items'])
194
+ yield from (cls._from_dict(item) for item in page['items'])
184
195
  next_page_uri = page['next_page_uri']
185
196
 
186
197
 
@@ -15,7 +15,7 @@ class CardActivation(Creatable):
15
15
  created_at: dt.datetime
16
16
  user_id: str
17
17
  ip_address: str
18
- card_uri: Optional[str]
18
+ card_uri: Optional[str] = None
19
19
  success: bool
20
20
 
21
21
  @classmethod
@@ -42,7 +42,9 @@ class CardActivation(Creatable):
42
42
  exp_year=exp_year,
43
43
  cvv2=cvv2,
44
44
  )
45
- return cls._create(session=session, **req.dict())
45
+ return cast(
46
+ 'CardActivation', cls._create(session=session, **req.model_dump())
47
+ )
46
48
 
47
49
  @property
48
50
  def card(self) -> Optional[Card]:
@@ -14,6 +14,9 @@ from .resources import retrieve_uri, retrieve_uris
14
14
 
15
15
 
16
16
  class CardTransaction(Transaction):
17
+ def __init__(self, *args, **kwargs):
18
+ super(CardTransaction, self).__init__(*args, **kwargs)
19
+
17
20
  _resource: ClassVar = 'card_transactions'
18
21
  _query_params: ClassVar = CardTransactionQuery
19
22
 
@@ -24,7 +27,7 @@ class CardTransaction(Transaction):
24
27
  card_last4: str
25
28
  card_type: CardType
26
29
  metadata: dict
27
- error_type: Optional[CardErrorType]
30
+ error_type: Optional[CardErrorType] = None
28
31
 
29
32
  @property # type: ignore
30
33
  def related_card_transactions(self) -> Optional[List['CardTransaction']]:
@@ -18,11 +18,11 @@ class CardValidation(Creatable):
18
18
  user_id: str
19
19
  card_status: CardStatus
20
20
  card_type: CardType
21
- is_valid_cvv: Optional[bool]
22
- is_valid_cvv2: Optional[bool]
23
- is_valid_icvv: Optional[bool]
24
- is_valid_pin_block: Optional[bool]
25
- is_valid_exp_date: Optional[bool]
21
+ is_valid_cvv: Optional[bool] = None
22
+ is_valid_cvv2: Optional[bool] = None
23
+ is_valid_icvv: Optional[bool] = None
24
+ is_valid_pin_block: Optional[bool] = None
25
+ is_valid_exp_date: Optional[bool] = None
26
26
  is_pin_attempts_exceeded: bool
27
27
  is_expired: bool
28
28
  platform_id: Optional[str] = None
@@ -37,7 +37,7 @@ class CardValidation(Creatable):
37
37
  exp_month: Optional[int] = None,
38
38
  exp_year: Optional[int] = None,
39
39
  pin_block: Optional[str] = None,
40
- pin_attempts_exceeded: Optional[str] = None,
40
+ pin_attempts_exceeded: Optional[bool] = None,
41
41
  *,
42
42
  session: Session = global_session,
43
43
  ) -> 'CardValidation':
@@ -52,7 +52,7 @@ class CardValidation(Creatable):
52
52
  pin_attempts_exceeded=pin_attempts_exceeded,
53
53
  )
54
54
  return cast(
55
- 'CardValidation', cls._create(session=session, **req.dict())
55
+ 'CardValidation', cls._create(session=session, **req.model_dump())
56
56
  )
57
57
 
58
58
  @property
@@ -1,5 +1,5 @@
1
1
  import datetime as dt
2
- from typing import ClassVar, Optional
2
+ from typing import ClassVar, Optional, cast
3
3
 
4
4
  from cuenca_validations.types import (
5
5
  CardFundingType,
@@ -21,12 +21,12 @@ class Card(Retrievable, Queryable, Creatable, Updateable):
21
21
  _resource: ClassVar = 'cards'
22
22
  _query_params: ClassVar = CardQuery
23
23
 
24
- user_id: Optional[str]
24
+ user_id: Optional[str] = None
25
25
  number: str
26
26
  exp_month: int
27
27
  exp_year: int
28
28
  cvv2: str
29
- pin: Optional[str]
29
+ pin: Optional[str] = None
30
30
  type: CardType
31
31
  status: CardStatus
32
32
  issuer: CardIssuer
@@ -81,7 +81,7 @@ class Card(Retrievable, Queryable, Creatable, Updateable):
81
81
  card_holder_user_id=card_holder_user_id,
82
82
  is_dynamic_cvv=is_dynamic_cvv,
83
83
  )
84
- return cls._create(session=session, **req.dict())
84
+ return cast('Card', cls._create(session=session, **req.dict()))
85
85
 
86
86
  @classmethod
87
87
  def update(
@@ -106,7 +106,8 @@ class Card(Retrievable, Queryable, Creatable, Updateable):
106
106
  req = CardUpdateRequest(
107
107
  status=status, pin_block=pin_block, is_dynamic_cvv=is_dynamic_cvv
108
108
  )
109
- return cls._update(card_id, session=session, **req.dict())
109
+ resp = cls._update(card_id, session=session, **req.dict())
110
+ return cast('Card', resp)
110
111
 
111
112
  @classmethod
112
113
  def deactivate(
@@ -117,4 +118,4 @@ class Card(Retrievable, Queryable, Creatable, Updateable):
117
118
  """
118
119
  url = f'{cls._resource}/{card_id}'
119
120
  resp = session.delete(url)
120
- return cls(**resp)
121
+ return cast('Card', cls._from_dict(resp))
@@ -1,4 +1,4 @@
1
- from typing import ClassVar
1
+ from typing import ClassVar, cast
2
2
 
3
3
  from ..http import Session, session as global_session
4
4
  from .base import Creatable, Queryable, Retrievable
@@ -11,4 +11,4 @@ class Clabe(Creatable, Queryable, Retrievable):
11
11
 
12
12
  @classmethod
13
13
  def create(cls, session: Session = global_session):
14
- return cls._create(session=session)
14
+ return cast('Clabe', cls._create(session=session))
@@ -1,5 +1,5 @@
1
1
  import datetime as dt
2
- from typing import ClassVar, Optional
2
+ from typing import ClassVar, Optional, cast
3
3
 
4
4
  from cuenca_validations.types import (
5
5
  Country,
@@ -8,6 +8,7 @@ from cuenca_validations.types import (
8
8
  State,
9
9
  )
10
10
  from cuenca_validations.types.identities import CurpField
11
+ from pydantic import ConfigDict, Field
11
12
 
12
13
  from ..http import Session, session as global_session
13
14
  from .base import Creatable, Retrievable
@@ -17,44 +18,43 @@ class CurpValidation(Creatable, Retrievable):
17
18
  _resource: ClassVar = 'curp_validations'
18
19
 
19
20
  created_at: dt.datetime
20
- names: Optional[str] = None
21
- first_surname: Optional[str] = None
22
- second_surname: Optional[str] = None
23
- date_of_birth: Optional[dt.date] = None
24
- country_of_birth: Optional[Country] = None
25
- state_of_birth: Optional[State] = None
26
- gender: Optional[Gender] = None
27
- nationality: Optional[Country] = None
28
- manual_curp: Optional[CurpField] = None
29
- calculated_curp: CurpField
30
- validated_curp: Optional[CurpField] = None
31
- renapo_curp_match: bool
32
- renapo_full_match: bool
33
-
34
- class Config:
35
- fields = {
36
- 'names': {'description': 'Official name from Renapo'},
37
- 'first_surname': {'description': 'Official surname from Renapo'},
38
- 'second_surname': {'description': 'Official surname from Renapo'},
39
- 'country_of_birth': {'description': 'In format ISO 3166 Alpha-2'},
40
- 'state_of_birth': {'description': 'In format ISO 3166 Alpha-2'},
41
- 'nationality': {'description': 'In format ISO 3166 Alpha-2'},
42
- 'manual_curp': {'description': 'curp provided in request'},
43
- 'calculated_curp': {
44
- 'description': 'Calculated CURP based on request data'
45
- },
46
- 'validated_curp': {
47
- 'description': 'CURP validated in Renapo, null if not exists'
48
- },
49
- 'renapo_curp_match': {
50
- 'description': 'True if CURP exists and is valid'
51
- },
52
- 'renapo_full_match': {
53
- 'description': 'True if all fields provided match the response'
54
- ' from RENAPO. Accents in names are ignored'
55
- },
56
- }
57
- schema_extra = {
21
+ names: Optional[str] = Field(None, description='Official name from Renapo')
22
+ first_surname: Optional[str] = Field(
23
+ None, description='Official surname from Renapo'
24
+ )
25
+ second_surname: Optional[str] = Field(
26
+ None, description='Official surname from Renapo'
27
+ )
28
+ date_of_birth: Optional[dt.date] = Field(
29
+ None, description='In format ISO 3166 Alpha-2'
30
+ )
31
+ country_of_birth: Optional[Country] = Field(
32
+ None, description='In format ISO 3166 Alpha-2'
33
+ )
34
+ state_of_birth: Optional[State] = Field(None, description='State of birth')
35
+ gender: Optional[Gender] = Field(None, description='Gender')
36
+ nationality: Optional[Country] = Field(
37
+ None, description='In format ISO 3166 Alpha-2'
38
+ )
39
+ manual_curp: Optional[CurpField] = Field(
40
+ None, description='curp provided in request'
41
+ )
42
+ calculated_curp: CurpField = Field(
43
+ ..., description='Calculated CURP based on request data'
44
+ )
45
+ validated_curp: Optional[CurpField] = Field(
46
+ None, description='CURP validated in Renapo, null if not exists'
47
+ )
48
+ renapo_curp_match: bool = Field(
49
+ ..., description='True if CURP exists and is valid'
50
+ )
51
+ renapo_full_match: bool = Field(
52
+ ...,
53
+ description='True if all fields provided match the response from '
54
+ 'RENAPO. Accents in names are ignored',
55
+ )
56
+ model_config = ConfigDict(
57
+ json_schema_extra={
58
58
  'example': {
59
59
  'id': 'CVNEUInh69SuKXXmK95sROwQ',
60
60
  'created_at': '2019-08-24T14:15:22Z',
@@ -72,7 +72,8 @@ class CurpValidation(Creatable, Retrievable):
72
72
  'renapo_curp_match': True,
73
73
  'renapo_full_match': True,
74
74
  }
75
- }
75
+ },
76
+ )
76
77
 
77
78
  @classmethod
78
79
  def create(
@@ -94,8 +95,11 @@ class CurpValidation(Creatable, Retrievable):
94
95
  second_surname=second_surname,
95
96
  date_of_birth=date_of_birth,
96
97
  state_of_birth=state_of_birth,
97
- country_of_birth=country_of_birth,
98
+ country_of_birth=cast(Country, country_of_birth),
98
99
  gender=gender,
99
100
  manual_curp=manual_curp,
100
101
  )
101
- return cls._create(session=session, **req.dict())
102
+ return cast(
103
+ 'CurpValidation',
104
+ cls._create(session=session, **req.model_dump()),
105
+ )
@@ -13,7 +13,7 @@ class Deposit(Transaction):
13
13
 
14
14
  network: DepositNetwork
15
15
  source_uri: str
16
- tracking_key: Optional[str] # clave rastreo if network is SPEI
16
+ tracking_key: Optional[str] = None # clave rastreo if network is SPEI
17
17
 
18
18
  @property # type: ignore
19
19
  def source(self) -> Account: