Monzo-API 1.2.5__tar.gz → 1.2.7__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.
- {monzo_api-1.2.5 → monzo_api-1.2.7/Monzo_API.egg-info}/PKG-INFO +2 -1
- {monzo_api-1.2.5/Monzo_API.egg-info → monzo_api-1.2.7}/PKG-INFO +2 -1
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/authentication.py +22 -21
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/account.py +6 -7
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/balance.py +1 -1
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/feed_item.py +9 -11
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/monzo.py +1 -1
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/pot.py +14 -14
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/receipt.py +38 -38
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/transaction.py +23 -25
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/webhooks.py +2 -4
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/handlers/filesystem.py +1 -2
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/handlers/storage.py +1 -2
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/helpers.py +2 -2
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/httpio.py +5 -5
- {monzo_api-1.2.5 → monzo_api-1.2.7}/pyproject.toml +2 -9
- {monzo_api-1.2.5 → monzo_api-1.2.7}/tests/test_authentication.py +1 -1
- {monzo_api-1.2.5 → monzo_api-1.2.7}/tests/test_endpoints.py +21 -17
- {monzo_api-1.2.5 → monzo_api-1.2.7}/tests/test_httpio_errors.py +3 -4
- {monzo_api-1.2.5 → monzo_api-1.2.7}/tests/test_payload.py +4 -5
- {monzo_api-1.2.5 → monzo_api-1.2.7}/LICENSE +0 -0
- {monzo_api-1.2.5 → monzo_api-1.2.7}/Monzo_API.egg-info/SOURCES.txt +0 -0
- {monzo_api-1.2.5 → monzo_api-1.2.7}/Monzo_API.egg-info/dependency_links.txt +0 -0
- {monzo_api-1.2.5 → monzo_api-1.2.7}/Monzo_API.egg-info/top_level.txt +0 -0
- {monzo_api-1.2.5 → monzo_api-1.2.7}/README.rst +0 -0
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/__init__.py +0 -0
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/__init__.py +0 -0
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/attachment.py +3 -3
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/endpoints/whoami.py +0 -0
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/exceptions.py +0 -0
- {monzo_api-1.2.5 → monzo_api-1.2.7}/monzo/handlers/__init__.py +0 -0
- {monzo_api-1.2.5 → monzo_api-1.2.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Monzo-API
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
4
4
|
Summary: Package to interact with the API provided by Monzo bank
|
|
5
5
|
Author-email: Peter McDonald <git@petermcdonald.co.uk>
|
|
6
6
|
License: MIT License
|
|
@@ -37,6 +37,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
37
37
|
Classifier: Programming Language :: Python :: 3.13
|
|
38
38
|
Classifier: Programming Language :: Python :: 3.14
|
|
39
39
|
Classifier: Programming Language :: Python :: 3.15
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.16
|
|
40
41
|
Classifier: Topic :: Office/Business :: Financial
|
|
41
42
|
Classifier: Typing :: Typed
|
|
42
43
|
Requires-Python: >=3.12
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Monzo-API
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
4
4
|
Summary: Package to interact with the API provided by Monzo bank
|
|
5
5
|
Author-email: Peter McDonald <git@petermcdonald.co.uk>
|
|
6
6
|
License: MIT License
|
|
@@ -37,6 +37,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
37
37
|
Classifier: Programming Language :: Python :: 3.13
|
|
38
38
|
Classifier: Programming Language :: Python :: 3.14
|
|
39
39
|
Classifier: Programming Language :: Python :: 3.15
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.16
|
|
40
41
|
Classifier: Topic :: Office/Business :: Financial
|
|
41
42
|
Classifier: Typing :: Typed
|
|
42
43
|
Requires-Python: >=3.12
|
|
@@ -6,7 +6,6 @@ import secrets
|
|
|
6
6
|
from pathlib import Path, PurePath
|
|
7
7
|
from tempfile import gettempdir
|
|
8
8
|
from time import time
|
|
9
|
-
from typing import List
|
|
10
9
|
|
|
11
10
|
from monzo.exceptions import MonzoAuthenticationError, MonzoError, MonzoHTTPError
|
|
12
11
|
from monzo.handlers.storage import Storage
|
|
@@ -15,8 +14,10 @@ from monzo.httpio import DEFAULT_TIMEOUT, REQUEST_RESPONSE_TYPE, HttpIO
|
|
|
15
14
|
MONZO_AUTH_URL = "https://auth.monzo.com"
|
|
16
15
|
MONZO_API_URL = "https://api.monzo.com"
|
|
17
16
|
|
|
17
|
+
logger: logging.Logger = logging.getLogger(name=__name__)
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
class Authentication:
|
|
20
21
|
"""
|
|
21
22
|
Class to manage authentication.
|
|
22
23
|
|
|
@@ -58,7 +59,7 @@ class Authentication(object):
|
|
|
58
59
|
self._access_token_expiry: int = access_token_expiry
|
|
59
60
|
self._client_id: str = client_id
|
|
60
61
|
self._client_secret: str = client_secret
|
|
61
|
-
self._handlers:
|
|
62
|
+
self._handlers: list[Storage] = []
|
|
62
63
|
self._redirect_url: str = redirect_url
|
|
63
64
|
self._refresh_token: str = refresh_token
|
|
64
65
|
|
|
@@ -68,17 +69,17 @@ class Authentication(object):
|
|
|
68
69
|
|
|
69
70
|
Args:
|
|
70
71
|
authorization_token: Authorization code provided by Monzo
|
|
71
|
-
state_token: Pre
|
|
72
|
+
state_token: Pre-agreed state token to validate against
|
|
72
73
|
|
|
73
74
|
Raises:
|
|
74
75
|
MonzoAuthenticationError On missing authorization token or mismatching state tokens
|
|
75
76
|
"""
|
|
76
|
-
|
|
77
|
+
logger.debug(msg="Attempting authentication")
|
|
77
78
|
if not authorization_token:
|
|
78
|
-
|
|
79
|
+
logger.debug(msg="Authentication - Missing token")
|
|
79
80
|
raise MonzoAuthenticationError("Code missing from response")
|
|
80
81
|
if state_token != self.state_token:
|
|
81
|
-
|
|
82
|
+
logger.debug(msg="Authentication - state token mismatch")
|
|
82
83
|
raise MonzoAuthenticationError("State tokens do not match")
|
|
83
84
|
tmp_file_name = "monzo"
|
|
84
85
|
tmp_file_path = PurePath(gettempdir(), tmp_file_name)
|
|
@@ -87,7 +88,7 @@ class Authentication(object):
|
|
|
87
88
|
|
|
88
89
|
def logout(self) -> None:
|
|
89
90
|
"""Invalidate the access token."""
|
|
90
|
-
|
|
91
|
+
logger.debug(msg="Invalidating token")
|
|
91
92
|
self.make_request(path="/oauth2/logout", method="post")
|
|
92
93
|
|
|
93
94
|
def make_request(
|
|
@@ -111,10 +112,10 @@ class Authentication(object):
|
|
|
111
112
|
timeout: Timeout in seconds for the request
|
|
112
113
|
|
|
113
114
|
Returns:
|
|
114
|
-
Dictionary containing headers and data from query response
|
|
115
|
+
Dictionary containing headers and data from a query response
|
|
115
116
|
|
|
116
117
|
Raises:
|
|
117
|
-
MonzoHTTPError: On using invalid method
|
|
118
|
+
MonzoHTTPError: On using an invalid method
|
|
118
119
|
"""
|
|
119
120
|
if self._access_token and self._access_token_expiry - time() < 0:
|
|
120
121
|
self.refresh_access()
|
|
@@ -141,9 +142,9 @@ class Authentication(object):
|
|
|
141
142
|
Raises:
|
|
142
143
|
MonzoAuthenticationError: On lack of refresh token or failure to refresh a token
|
|
143
144
|
"""
|
|
144
|
-
|
|
145
|
+
logger.debug(msg="Fetching new token")
|
|
145
146
|
if not self.refresh_token:
|
|
146
|
-
|
|
147
|
+
logger.debug(msg="Unable to fetch new token without a refresh token")
|
|
147
148
|
raise MonzoAuthenticationError("Unable to refresh without a refresh token")
|
|
148
149
|
data = {
|
|
149
150
|
"grant_type": "refresh_token",
|
|
@@ -154,9 +155,9 @@ class Authentication(object):
|
|
|
154
155
|
conn = HttpIO(MONZO_API_URL)
|
|
155
156
|
try:
|
|
156
157
|
res = conn.post(path="/oauth2/token", data=data)
|
|
157
|
-
self._populate_tokens(res)
|
|
158
|
+
self._populate_tokens(response=res)
|
|
158
159
|
except MonzoError as exc:
|
|
159
|
-
|
|
160
|
+
logger.debug(msg="Failed to fetch new token")
|
|
160
161
|
raise MonzoAuthenticationError("Could not refresh the access token") from exc
|
|
161
162
|
|
|
162
163
|
@property
|
|
@@ -182,7 +183,7 @@ class Authentication(object):
|
|
|
182
183
|
@access_token_expiry.setter
|
|
183
184
|
def access_token_expiry(self, expires_in: int) -> None:
|
|
184
185
|
"""
|
|
185
|
-
Setter for access token expiry property.
|
|
186
|
+
Setter for the access token expiry property.
|
|
186
187
|
|
|
187
188
|
Args:
|
|
188
189
|
expires_in: number of seconds until the token expires
|
|
@@ -241,7 +242,7 @@ class Authentication(object):
|
|
|
241
242
|
Raises:
|
|
242
243
|
MonzoAuthenticationError On failure to create a token
|
|
243
244
|
"""
|
|
244
|
-
|
|
245
|
+
logger.debug(msg="Authentication - swapping authorization token for an access token")
|
|
245
246
|
data = {
|
|
246
247
|
"grant_type": "authorization_code",
|
|
247
248
|
"client_id": self._client_id,
|
|
@@ -250,10 +251,10 @@ class Authentication(object):
|
|
|
250
251
|
"code": authorization_token,
|
|
251
252
|
}
|
|
252
253
|
try:
|
|
253
|
-
res = self.make_request("/oauth2/token", authenticated=False, method="post", data=data)
|
|
254
|
-
self._populate_tokens(res)
|
|
254
|
+
res = self.make_request(path="/oauth2/token", authenticated=False, method="post", data=data)
|
|
255
|
+
self._populate_tokens(response=res)
|
|
255
256
|
except MonzoError as exc:
|
|
256
|
-
|
|
257
|
+
logger.debug(msg=f"Could not fetch access token {exc}")
|
|
257
258
|
raise MonzoAuthenticationError("Could not fetch a valid access token") from exc
|
|
258
259
|
|
|
259
260
|
def _populate_tokens(self, response: REQUEST_RESPONSE_TYPE) -> None:
|
|
@@ -263,7 +264,7 @@ class Authentication(object):
|
|
|
263
264
|
Args:
|
|
264
265
|
response: Response from an auth request.
|
|
265
266
|
"""
|
|
266
|
-
|
|
267
|
+
logger.debug(msg="Populating tokens")
|
|
267
268
|
self._access_token = response["data"]["access_token"]
|
|
268
269
|
self.access_token_expiry = response["data"]["expires_in"]
|
|
269
270
|
self._refresh_token = ""
|
|
@@ -286,5 +287,5 @@ class Authentication(object):
|
|
|
286
287
|
Args:
|
|
287
288
|
handler: Credential handler implementing Storage
|
|
288
289
|
"""
|
|
289
|
-
|
|
290
|
+
logger.debug(msg="Registered a new callback handler")
|
|
290
291
|
self._handlers.append(handler)
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from datetime import datetime
|
|
6
|
-
from typing import List, Optional
|
|
7
6
|
|
|
8
7
|
from monzo.authentication import Authentication
|
|
9
8
|
from monzo.endpoints.balance import Balance
|
|
@@ -36,10 +35,10 @@ class Account(Monzo):
|
|
|
36
35
|
"_account_id",
|
|
37
36
|
"_auth",
|
|
38
37
|
"_balance",
|
|
38
|
+
"_closed",
|
|
39
39
|
"_created",
|
|
40
40
|
"_description",
|
|
41
41
|
"_has_balance",
|
|
42
|
-
"_closed",
|
|
43
42
|
]
|
|
44
43
|
|
|
45
44
|
def __init__(
|
|
@@ -62,7 +61,7 @@ class Account(Monzo):
|
|
|
62
61
|
"""
|
|
63
62
|
self._auth: Authentication = auth
|
|
64
63
|
self._account_id: str = account_id
|
|
65
|
-
self._balance:
|
|
64
|
+
self._balance: Balance | None = None
|
|
66
65
|
self._created: datetime = created
|
|
67
66
|
self._description: str = description
|
|
68
67
|
self._has_balance: bool = True
|
|
@@ -89,13 +88,13 @@ class Account(Monzo):
|
|
|
89
88
|
return next(
|
|
90
89
|
(
|
|
91
90
|
MONZO_ACCOUNT_TYPES[account_type]
|
|
92
|
-
for account_type in MONZO_ACCOUNT_TYPES
|
|
91
|
+
for account_type in MONZO_ACCOUNT_TYPES
|
|
93
92
|
if self.description.lower().startswith(account_type)
|
|
94
93
|
),
|
|
95
94
|
"UNKNOWN",
|
|
96
95
|
)
|
|
97
96
|
|
|
98
|
-
def fetch_balance(self) ->
|
|
97
|
+
def fetch_balance(self) -> Balance | None:
|
|
99
98
|
"""
|
|
100
99
|
Fetch the live balance.
|
|
101
100
|
|
|
@@ -113,7 +112,7 @@ class Account(Monzo):
|
|
|
113
112
|
return self._balance
|
|
114
113
|
|
|
115
114
|
@property
|
|
116
|
-
def balance(self) ->
|
|
115
|
+
def balance(self) -> Balance | None:
|
|
117
116
|
"""
|
|
118
117
|
Property for balance.
|
|
119
118
|
|
|
@@ -158,7 +157,7 @@ class Account(Monzo):
|
|
|
158
157
|
return self._closed
|
|
159
158
|
|
|
160
159
|
@classmethod
|
|
161
|
-
def fetch(cls, auth: Authentication, account_type: str = "") ->
|
|
160
|
+
def fetch(cls, auth: Authentication, account_type: str = "") -> list[Account]:
|
|
162
161
|
"""
|
|
163
162
|
Implement and instantiates an Account object.
|
|
164
163
|
|
|
@@ -14,7 +14,7 @@ class Balance(Monzo):
|
|
|
14
14
|
along with the balance property. Otherwise, you can fetch an account balance using the fetch class method.
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
__slots__ =
|
|
17
|
+
__slots__ = ("_balance", "_currency", "_spend_today", "_total_balance")
|
|
18
18
|
|
|
19
19
|
def __init__(
|
|
20
20
|
self,
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Dict, Optional
|
|
6
|
-
|
|
7
5
|
from monzo.authentication import Authentication
|
|
8
6
|
from monzo.endpoints.monzo import Monzo
|
|
9
7
|
from monzo.exceptions import MonzoArgumentError
|
|
@@ -46,7 +44,7 @@ class FeedItem(Monzo):
|
|
|
46
44
|
auth: Authentication,
|
|
47
45
|
account_id: str,
|
|
48
46
|
feed_type: str,
|
|
49
|
-
params:
|
|
47
|
+
params: dict[str, str],
|
|
50
48
|
url: str = "",
|
|
51
49
|
):
|
|
52
50
|
"""
|
|
@@ -57,15 +55,15 @@ class FeedItem(Monzo):
|
|
|
57
55
|
account_id: ID for the account to create the feed item for
|
|
58
56
|
feed_type: Type of feed item to create (must be in FEED_ITEM_TYPES)
|
|
59
57
|
params: Parameters for the feed item.
|
|
60
|
-
url: Optional URL for feed item
|
|
58
|
+
url: Optional URL for a feed item
|
|
61
59
|
"""
|
|
62
60
|
self._account_id: str = account_id
|
|
63
61
|
self._feed_type: str = feed_type
|
|
64
|
-
self._params:
|
|
65
|
-
self._url:
|
|
62
|
+
self._params: dict[str, str] = params
|
|
63
|
+
self._url: str | None = url
|
|
66
64
|
super().__init__(auth=auth)
|
|
67
65
|
|
|
68
|
-
def _validate_feed_params(self) ->
|
|
66
|
+
def _validate_feed_params(self) -> dict[str, str]:
|
|
69
67
|
"""
|
|
70
68
|
Clean the params dictionary with the valid params for the feed type.
|
|
71
69
|
|
|
@@ -73,7 +71,7 @@ class FeedItem(Monzo):
|
|
|
73
71
|
MonzoArgumentError: On missing required parameters
|
|
74
72
|
|
|
75
73
|
Returns:
|
|
76
|
-
Dictionary of parameters only
|
|
74
|
+
Dictionary of parameters only contains valid keys
|
|
77
75
|
"""
|
|
78
76
|
if self._feed_type.lower() not in FEED_ITEM_TYPES:
|
|
79
77
|
raise MonzoArgumentError("Feed type appears invalid")
|
|
@@ -100,7 +98,7 @@ class FeedItem(Monzo):
|
|
|
100
98
|
}
|
|
101
99
|
if self._url:
|
|
102
100
|
data["url"] = self._url
|
|
103
|
-
for parameter in parameters
|
|
101
|
+
for parameter in parameters:
|
|
104
102
|
data[f"params[{parameter}]"] = parameters[parameter]
|
|
105
103
|
self._monzo_auth.make_request(path="/feed", method="POST", data=data)
|
|
106
104
|
|
|
@@ -110,7 +108,7 @@ class FeedItem(Monzo):
|
|
|
110
108
|
auth: Authentication,
|
|
111
109
|
account_id: str,
|
|
112
110
|
feed_type: str,
|
|
113
|
-
params:
|
|
111
|
+
params: dict[str, str],
|
|
114
112
|
url: str = "",
|
|
115
113
|
) -> FeedItem:
|
|
116
114
|
"""
|
|
@@ -121,7 +119,7 @@ class FeedItem(Monzo):
|
|
|
121
119
|
account_id: ID for the account to create the feed item for
|
|
122
120
|
feed_type: Type of feed item to create (must be in FEED_ITEM_TYPES)
|
|
123
121
|
params: Parameters for the feed item.
|
|
124
|
-
url: Optional URL for feed item
|
|
122
|
+
url: Optional URL for a feed item
|
|
125
123
|
"""
|
|
126
124
|
feed_item = FeedItem(
|
|
127
125
|
auth=auth,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from datetime import datetime
|
|
6
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
7
7
|
|
|
8
8
|
from monzo.authentication import Authentication
|
|
9
9
|
from monzo.endpoints.balance import Balance
|
|
@@ -19,22 +19,22 @@ class Pot(Monzo):
|
|
|
19
19
|
Class provides methods to fetch pots as well as depositing and withdrawing from pots.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
__slots__ =
|
|
23
|
-
"_pot_id",
|
|
24
|
-
"_name",
|
|
25
|
-
"_style",
|
|
22
|
+
__slots__ = (
|
|
26
23
|
"_balance",
|
|
27
|
-
"_currency",
|
|
28
24
|
"_created",
|
|
29
|
-
"
|
|
25
|
+
"_currency",
|
|
30
26
|
"_deleted",
|
|
31
27
|
"_goal_amount",
|
|
32
28
|
"_has_round_up",
|
|
33
|
-
"_round_up_multiplier",
|
|
34
|
-
"_pot_type",
|
|
35
29
|
"_locked",
|
|
36
30
|
"_locked_until",
|
|
37
|
-
|
|
31
|
+
"_name",
|
|
32
|
+
"_pot_id",
|
|
33
|
+
"_pot_type",
|
|
34
|
+
"_round_up_multiplier",
|
|
35
|
+
"_style",
|
|
36
|
+
"_updated",
|
|
37
|
+
)
|
|
38
38
|
|
|
39
39
|
def __init__(
|
|
40
40
|
self,
|
|
@@ -186,7 +186,7 @@ class Pot(Monzo):
|
|
|
186
186
|
Property for the pot round up multiplier.
|
|
187
187
|
|
|
188
188
|
Returns:
|
|
189
|
-
int object for the
|
|
189
|
+
int object for the pot round up multiplier else None object if roundup is disabled
|
|
190
190
|
"""
|
|
191
191
|
return self._round_up_multiplier
|
|
192
192
|
|
|
@@ -270,7 +270,7 @@ class Pot(Monzo):
|
|
|
270
270
|
return cls._update_pot(pot=pot, data=res["data"])
|
|
271
271
|
|
|
272
272
|
@classmethod
|
|
273
|
-
def fetch(cls, auth: Authentication, account_id: str) ->
|
|
273
|
+
def fetch(cls, auth: Authentication, account_id: str) -> list[Pot]:
|
|
274
274
|
"""
|
|
275
275
|
Fetch a list of pots associated with an account.
|
|
276
276
|
|
|
@@ -309,7 +309,7 @@ class Pot(Monzo):
|
|
|
309
309
|
return pot_list
|
|
310
310
|
|
|
311
311
|
@classmethod
|
|
312
|
-
def fetch_single(cls, auth: Authentication, account_id: str, pot_id: str) ->
|
|
312
|
+
def fetch_single(cls, auth: Authentication, account_id: str, pot_id: str) -> Pot | None:
|
|
313
313
|
"""
|
|
314
314
|
Fetch a pot associated with an account with the given pot id.
|
|
315
315
|
|
|
@@ -361,7 +361,7 @@ class Pot(Monzo):
|
|
|
361
361
|
return cls._update_pot(pot=pot, data=res["data"])
|
|
362
362
|
|
|
363
363
|
@classmethod
|
|
364
|
-
def _update_pot(cls, pot: Pot, data:
|
|
364
|
+
def _update_pot(cls, pot: Pot, data: dict[str, Any]) -> Pot:
|
|
365
365
|
"""
|
|
366
366
|
Update a provided pot from a result received from a request.
|
|
367
367
|
|
|
@@ -3,23 +3,23 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from json import dumps
|
|
6
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
7
7
|
|
|
8
8
|
from monzo.authentication import Authentication
|
|
9
9
|
from monzo.endpoints.monzo import Monzo
|
|
10
10
|
|
|
11
11
|
RECEIPTS_PATH = "/transaction-receipts"
|
|
12
12
|
|
|
13
|
-
ITEM_TYPE =
|
|
13
|
+
ITEM_TYPE = dict[
|
|
14
14
|
str,
|
|
15
|
-
|
|
15
|
+
float | int | None | str | list[dict[str, float | int | str | None]],
|
|
16
16
|
]
|
|
17
|
-
MERCHANT_TYPE =
|
|
18
|
-
PAYMENT_TYPE =
|
|
19
|
-
TAX_TYPE =
|
|
17
|
+
MERCHANT_TYPE = dict[str, bool | str]
|
|
18
|
+
PAYMENT_TYPE = dict[str, int | str]
|
|
19
|
+
TAX_TYPE = dict[str, int | str]
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
class ReceiptItem
|
|
22
|
+
class ReceiptItem:
|
|
23
23
|
"""
|
|
24
24
|
Class for Receipt Items.
|
|
25
25
|
|
|
@@ -62,7 +62,7 @@ class ReceiptItem(object):
|
|
|
62
62
|
self._quantity = quantity
|
|
63
63
|
self._tax = tax
|
|
64
64
|
self._unit = unit
|
|
65
|
-
self._sub_items:
|
|
65
|
+
self._sub_items: list[ReceiptItem] = []
|
|
66
66
|
|
|
67
67
|
def add_sub_item(self, sub_item: ReceiptItem):
|
|
68
68
|
"""
|
|
@@ -88,7 +88,7 @@ class ReceiptItem(object):
|
|
|
88
88
|
"tax": self._tax,
|
|
89
89
|
"unit": self._unit,
|
|
90
90
|
}
|
|
91
|
-
sub_item_list:
|
|
91
|
+
sub_item_list: list[Any] = [sub_item.as_dict() for sub_item in self._sub_items]
|
|
92
92
|
|
|
93
93
|
item["sub_items"] = sub_item_list
|
|
94
94
|
|
|
@@ -99,18 +99,18 @@ class Receipt(Monzo):
|
|
|
99
99
|
"""
|
|
100
100
|
Class to manage Receipts.
|
|
101
101
|
|
|
102
|
-
Class provides methods to create, fetch and delete receipts.
|
|
102
|
+
Class provides methods to create, fetch, and delete receipts.
|
|
103
103
|
"""
|
|
104
104
|
|
|
105
105
|
__slots__ = (
|
|
106
|
-
"_external_id",
|
|
107
|
-
"_transaction_id",
|
|
108
|
-
"_total",
|
|
109
106
|
"_currency",
|
|
107
|
+
"_external_id",
|
|
110
108
|
"_items",
|
|
111
|
-
"_taxes",
|
|
112
|
-
"_payments",
|
|
113
109
|
"_merchant",
|
|
110
|
+
"_payments",
|
|
111
|
+
"_taxes",
|
|
112
|
+
"_total",
|
|
113
|
+
"_transaction_id",
|
|
114
114
|
)
|
|
115
115
|
|
|
116
116
|
def __init__(
|
|
@@ -120,7 +120,7 @@ class Receipt(Monzo):
|
|
|
120
120
|
external_id: str,
|
|
121
121
|
transaction_total: int,
|
|
122
122
|
transaction_currency: str,
|
|
123
|
-
items:
|
|
123
|
+
items: list[ReceiptItem],
|
|
124
124
|
):
|
|
125
125
|
"""
|
|
126
126
|
Initialize Receipt.
|
|
@@ -137,9 +137,9 @@ class Receipt(Monzo):
|
|
|
137
137
|
self._transaction_id: str = transaction_id
|
|
138
138
|
self._total = transaction_total
|
|
139
139
|
self._currency = transaction_currency
|
|
140
|
-
self._items:
|
|
141
|
-
self._taxes:
|
|
142
|
-
self._payments:
|
|
140
|
+
self._items: list[ReceiptItem] = items
|
|
141
|
+
self._taxes: list[TAX_TYPE] = []
|
|
142
|
+
self._payments: list[PAYMENT_TYPE] = []
|
|
143
143
|
self._merchant: MERCHANT_TYPE = {}
|
|
144
144
|
|
|
145
145
|
super().__init__(auth=auth)
|
|
@@ -148,11 +148,11 @@ class Receipt(Monzo):
|
|
|
148
148
|
self,
|
|
149
149
|
name: str,
|
|
150
150
|
online: bool,
|
|
151
|
-
phone:
|
|
152
|
-
email:
|
|
153
|
-
store_name:
|
|
154
|
-
store_address:
|
|
155
|
-
store_postcode:
|
|
151
|
+
phone: str | None = None,
|
|
152
|
+
email: str | None = None,
|
|
153
|
+
store_name: str | None = None,
|
|
154
|
+
store_address: str | None = None,
|
|
155
|
+
store_postcode: str | None = None,
|
|
156
156
|
):
|
|
157
157
|
"""
|
|
158
158
|
Set the merchant for the receipt.
|
|
@@ -188,7 +188,7 @@ class Receipt(Monzo):
|
|
|
188
188
|
description: str,
|
|
189
189
|
amount: int,
|
|
190
190
|
currency: str,
|
|
191
|
-
tax_number:
|
|
191
|
+
tax_number: str | None = None,
|
|
192
192
|
):
|
|
193
193
|
"""
|
|
194
194
|
Add receipt tax item.
|
|
@@ -210,7 +210,7 @@ class Receipt(Monzo):
|
|
|
210
210
|
|
|
211
211
|
def _create(self) -> None:
|
|
212
212
|
"""Create the receipt."""
|
|
213
|
-
data = {
|
|
213
|
+
data: dict[str, Any] = {
|
|
214
214
|
"transaction_id": self._transaction_id,
|
|
215
215
|
"external_id": self._external_id,
|
|
216
216
|
"total": self._total,
|
|
@@ -219,7 +219,7 @@ class Receipt(Monzo):
|
|
|
219
219
|
"payments": self._payments,
|
|
220
220
|
"merchant": self._merchant,
|
|
221
221
|
}
|
|
222
|
-
receipt_items:
|
|
222
|
+
receipt_items: list[ITEM_TYPE] = [item.as_dict() for item in self._items]
|
|
223
223
|
|
|
224
224
|
data["items"] = receipt_items
|
|
225
225
|
|
|
@@ -261,7 +261,7 @@ class Receipt(Monzo):
|
|
|
261
261
|
return self._currency
|
|
262
262
|
|
|
263
263
|
@property
|
|
264
|
-
def receipt_items(self) ->
|
|
264
|
+
def receipt_items(self) -> list[ReceiptItem]:
|
|
265
265
|
"""
|
|
266
266
|
Property for the items in a receipt.
|
|
267
267
|
|
|
@@ -281,7 +281,7 @@ class Receipt(Monzo):
|
|
|
281
281
|
return self._merchant
|
|
282
282
|
|
|
283
283
|
@property
|
|
284
|
-
def receipt_payments(self) ->
|
|
284
|
+
def receipt_payments(self) -> list[PAYMENT_TYPE]:
|
|
285
285
|
"""
|
|
286
286
|
Property for the payments in a receipt.
|
|
287
287
|
|
|
@@ -291,7 +291,7 @@ class Receipt(Monzo):
|
|
|
291
291
|
return self._payments
|
|
292
292
|
|
|
293
293
|
@property
|
|
294
|
-
def receipt_taxes(self) ->
|
|
294
|
+
def receipt_taxes(self) -> list[TAX_TYPE]:
|
|
295
295
|
"""
|
|
296
296
|
Property for the taxes in a receipt.
|
|
297
297
|
|
|
@@ -347,7 +347,7 @@ class Receipt(Monzo):
|
|
|
347
347
|
receipt._delete()
|
|
348
348
|
|
|
349
349
|
@classmethod
|
|
350
|
-
def fetch(cls, auth: Authentication, external_id: str) ->
|
|
350
|
+
def fetch(cls, auth: Authentication, external_id: str) -> list[Receipt]:
|
|
351
351
|
"""
|
|
352
352
|
Fetch the receipt with the given external ID.
|
|
353
353
|
|
|
@@ -361,11 +361,11 @@ class Receipt(Monzo):
|
|
|
361
361
|
data = {"external_id": external_id}
|
|
362
362
|
res = auth.make_request(path=RECEIPTS_PATH, data=data)
|
|
363
363
|
receipt_data = res["data"]["receipt"]
|
|
364
|
-
receipt_items:
|
|
364
|
+
receipt_items: list[ReceiptItem] = []
|
|
365
365
|
for item in receipt_data["items"]:
|
|
366
|
-
quantity = float(item
|
|
367
|
-
tax = item
|
|
368
|
-
unit = item
|
|
366
|
+
quantity = float(item.get("quantity", 0.0)) if "quantity" in item else 0.0
|
|
367
|
+
tax = item.get("tax", 0) if "tax" in item else 0
|
|
368
|
+
unit = item.get("unit", "") if "unit" in item else ""
|
|
369
369
|
receipt_item: ReceiptItem = ReceiptItem(
|
|
370
370
|
description=item["description"],
|
|
371
371
|
amount=item["amount"],
|
|
@@ -376,9 +376,9 @@ class Receipt(Monzo):
|
|
|
376
376
|
)
|
|
377
377
|
|
|
378
378
|
for sub_item in item["sub_items"]:
|
|
379
|
-
sub_item_quantity = sub_item
|
|
380
|
-
sub_item_tax = sub_item
|
|
381
|
-
sub_item_unit = sub_item
|
|
379
|
+
sub_item_quantity = sub_item.get("quantity", 0.0) if "quantity" in sub_item else 0.0
|
|
380
|
+
sub_item_tax = sub_item.get("tax", 0) if "tax" in sub_item else 0
|
|
381
|
+
sub_item_unit = sub_item.get("unit", "") if "unit" in sub_item else ""
|
|
382
382
|
receipt_sub_item = ReceiptItem(
|
|
383
383
|
description=sub_item["description"],
|
|
384
384
|
amount=sub_item["amount"],
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from datetime import datetime
|
|
6
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
7
7
|
|
|
8
8
|
from monzo.authentication import Authentication
|
|
9
9
|
from monzo.endpoints.monzo import Monzo
|
|
@@ -56,7 +56,7 @@ class Transaction(Monzo):
|
|
|
56
56
|
"_user_id",
|
|
57
57
|
]
|
|
58
58
|
|
|
59
|
-
def __init__(self, auth: Authentication, transaction_data:
|
|
59
|
+
def __init__(self, auth: Authentication, transaction_data: dict[str, Any]):
|
|
60
60
|
"""
|
|
61
61
|
Initialize Transaction.
|
|
62
62
|
|
|
@@ -76,7 +76,7 @@ class Transaction(Monzo):
|
|
|
76
76
|
"can_match_transactions_in_categorization"
|
|
77
77
|
]
|
|
78
78
|
self._can_split_the_bill: bool = transaction_data["can_split_the_bill"]
|
|
79
|
-
self._categories:
|
|
79
|
+
self._categories: dict[str, int | str] = transaction_data["categories"]
|
|
80
80
|
self._category: str = transaction_data["category"]
|
|
81
81
|
self._counterparty = transaction_data["counterparty"]
|
|
82
82
|
self._created: datetime = create_date(transaction_data["created"])
|
|
@@ -84,19 +84,19 @@ class Transaction(Monzo):
|
|
|
84
84
|
self._dedupe_id: str = transaction_data["dedupe_id"]
|
|
85
85
|
self._decline_reason: str = transaction_data.get("decline_reason", "")
|
|
86
86
|
self._description: str = transaction_data["description"]
|
|
87
|
-
self._fees:
|
|
87
|
+
self._fees: dict[str, Any] = transaction_data["fees"]
|
|
88
88
|
self._include_in_spending: bool = transaction_data["include_in_spending"]
|
|
89
|
-
self._international:
|
|
89
|
+
self._international: str | None = transaction_data["international"]
|
|
90
90
|
self._is_load: bool = transaction_data["is_load"]
|
|
91
91
|
self._labels: str = transaction_data["labels"]
|
|
92
92
|
self._local_amount: int = transaction_data["local_amount"]
|
|
93
93
|
self._local_currency: str = transaction_data["local_currency"]
|
|
94
94
|
self._merchant: str = transaction_data["merchant"]
|
|
95
|
-
self._metadata:
|
|
95
|
+
self._metadata: dict[str, str] = transaction_data["metadata"]
|
|
96
96
|
self._notes: str = transaction_data["notes"]
|
|
97
97
|
self._originator: bool = transaction_data["originator"]
|
|
98
98
|
self._scheme: str = transaction_data["scheme"]
|
|
99
|
-
self._settled:
|
|
99
|
+
self._settled: datetime | None = None
|
|
100
100
|
if transaction_data["settled"]:
|
|
101
101
|
self._settled = create_date(transaction_data["settled"])
|
|
102
102
|
self._transaction_id: str = transaction_data["id"]
|
|
@@ -131,12 +131,12 @@ class Transaction(Monzo):
|
|
|
131
131
|
Property to identify if the amount is pending.
|
|
132
132
|
|
|
133
133
|
Returns:
|
|
134
|
-
True if transaction is pending
|
|
134
|
+
True if a transaction is pending
|
|
135
135
|
"""
|
|
136
136
|
return self._amount_is_pending
|
|
137
137
|
|
|
138
138
|
@property
|
|
139
|
-
def atm_fees_detailed(self) ->
|
|
139
|
+
def atm_fees_detailed(self) -> str | None:
|
|
140
140
|
"""
|
|
141
141
|
Property for detailed atm fees.
|
|
142
142
|
|
|
@@ -146,7 +146,7 @@ class Transaction(Monzo):
|
|
|
146
146
|
return self._atm_fees_detailed
|
|
147
147
|
|
|
148
148
|
@property
|
|
149
|
-
def attachments(self) ->
|
|
149
|
+
def attachments(self) -> str | None:
|
|
150
150
|
"""
|
|
151
151
|
Property for attachments.
|
|
152
152
|
|
|
@@ -206,7 +206,7 @@ class Transaction(Monzo):
|
|
|
206
206
|
return self._can_split_the_bill
|
|
207
207
|
|
|
208
208
|
@property
|
|
209
|
-
def categories(self) ->
|
|
209
|
+
def categories(self) -> dict[str, int | str]:
|
|
210
210
|
"""
|
|
211
211
|
Property to identify categories a transaction is a member of.
|
|
212
212
|
|
|
@@ -226,7 +226,7 @@ class Transaction(Monzo):
|
|
|
226
226
|
return self._category
|
|
227
227
|
|
|
228
228
|
@property
|
|
229
|
-
def counterparty(self) ->
|
|
229
|
+
def counterparty(self) -> dict[str, str]:
|
|
230
230
|
"""
|
|
231
231
|
Property to identify counterparty.
|
|
232
232
|
|
|
@@ -288,7 +288,7 @@ class Transaction(Monzo):
|
|
|
288
288
|
return self._description
|
|
289
289
|
|
|
290
290
|
@property
|
|
291
|
-
def fees(self) ->
|
|
291
|
+
def fees(self) -> dict[str, Any]:
|
|
292
292
|
"""
|
|
293
293
|
Property for transaction fees.
|
|
294
294
|
|
|
@@ -308,7 +308,7 @@ class Transaction(Monzo):
|
|
|
308
308
|
return self._include_in_spending
|
|
309
309
|
|
|
310
310
|
@property
|
|
311
|
-
def international(self) ->
|
|
311
|
+
def international(self) -> str | None:
|
|
312
312
|
"""
|
|
313
313
|
UNCLEAR.
|
|
314
314
|
|
|
@@ -370,7 +370,7 @@ class Transaction(Monzo):
|
|
|
370
370
|
return self._merchant
|
|
371
371
|
|
|
372
372
|
@property
|
|
373
|
-
def metadata(self) ->
|
|
373
|
+
def metadata(self) -> dict[str, str]:
|
|
374
374
|
"""
|
|
375
375
|
Property for metadata associated with a transaction.
|
|
376
376
|
|
|
@@ -395,7 +395,7 @@ class Transaction(Monzo):
|
|
|
395
395
|
Property to identify if you are the originator of a transaction.
|
|
396
396
|
|
|
397
397
|
Returns:
|
|
398
|
-
True if you are the originator of a transaction otherwise False
|
|
398
|
+
True if you are the originator of a transaction, otherwise False
|
|
399
399
|
"""
|
|
400
400
|
return self._originator
|
|
401
401
|
|
|
@@ -412,7 +412,7 @@ class Transaction(Monzo):
|
|
|
412
412
|
return self._scheme
|
|
413
413
|
|
|
414
414
|
@property
|
|
415
|
-
def settled(self) ->
|
|
415
|
+
def settled(self) -> datetime | None:
|
|
416
416
|
"""
|
|
417
417
|
Property for when a transaction was settled.
|
|
418
418
|
|
|
@@ -432,7 +432,7 @@ class Transaction(Monzo):
|
|
|
432
432
|
return self._transaction_id
|
|
433
433
|
|
|
434
434
|
@property
|
|
435
|
-
def updated(self) ->
|
|
435
|
+
def updated(self) -> datetime | None:
|
|
436
436
|
"""
|
|
437
437
|
Property for when a transaction was updated.
|
|
438
438
|
|
|
@@ -477,9 +477,7 @@ class Transaction(Monzo):
|
|
|
477
477
|
self._metadata = res["data"]["transaction"]["metadata"]
|
|
478
478
|
|
|
479
479
|
@classmethod
|
|
480
|
-
def fetch_single(
|
|
481
|
-
cls, auth: Authentication, transaction_id: str, expand_on: str = "merchant"
|
|
482
|
-
) -> Optional[Transaction]:
|
|
480
|
+
def fetch_single(cls, auth: Authentication, transaction_id: str, expand_on: str = "merchant") -> Transaction | None:
|
|
483
481
|
"""
|
|
484
482
|
Fetch a transaction with a specific ID.
|
|
485
483
|
|
|
@@ -507,11 +505,11 @@ class Transaction(Monzo):
|
|
|
507
505
|
cls,
|
|
508
506
|
auth: Authentication,
|
|
509
507
|
account_id: str,
|
|
510
|
-
since:
|
|
511
|
-
before:
|
|
508
|
+
since: datetime | str | None = None,
|
|
509
|
+
before: datetime | None = None,
|
|
512
510
|
expand=None,
|
|
513
511
|
limit=30,
|
|
514
|
-
) ->
|
|
512
|
+
) -> list[Transaction]:
|
|
515
513
|
"""
|
|
516
514
|
Fetch a list of transaction.
|
|
517
515
|
|
|
@@ -524,7 +522,7 @@ class Transaction(Monzo):
|
|
|
524
522
|
limit: Number of transactions to return per request, max 100, default 30.
|
|
525
523
|
|
|
526
524
|
Returns:
|
|
527
|
-
List of
|
|
525
|
+
List of transactions
|
|
528
526
|
"""
|
|
529
527
|
if expand is None:
|
|
530
528
|
expand = []
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import List
|
|
6
|
-
|
|
7
5
|
from monzo.authentication import Authentication
|
|
8
6
|
from monzo.endpoints.monzo import Monzo
|
|
9
7
|
|
|
@@ -12,7 +10,7 @@ class Webhook(Monzo):
|
|
|
12
10
|
"""
|
|
13
11
|
Class to manage webhooks.
|
|
14
12
|
|
|
15
|
-
Class provides methods to create, fetch and delete webhooks.
|
|
13
|
+
Class provides methods to create, fetch, and delete webhooks.
|
|
16
14
|
"""
|
|
17
15
|
|
|
18
16
|
__slots__ = ["_account_id", "_url", "_webhook_id"]
|
|
@@ -104,7 +102,7 @@ class Webhook(Monzo):
|
|
|
104
102
|
webhook._delete()
|
|
105
103
|
|
|
106
104
|
@classmethod
|
|
107
|
-
def fetch(cls, auth: Authentication, account_id: str) ->
|
|
105
|
+
def fetch(cls, auth: Authentication, account_id: str) -> list[Webhook]:
|
|
108
106
|
"""
|
|
109
107
|
Fetch webhooks for an account.
|
|
110
108
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Class to store credentials on the file system."""
|
|
2
2
|
|
|
3
3
|
from json import dumps, loads
|
|
4
|
-
from typing import Dict, Union
|
|
5
4
|
|
|
6
5
|
from monzo.handlers.storage import Storage
|
|
7
6
|
|
|
@@ -20,7 +19,7 @@ class FileSystem(Storage):
|
|
|
20
19
|
"""
|
|
21
20
|
self._file = file
|
|
22
21
|
|
|
23
|
-
def fetch(self) ->
|
|
22
|
+
def fetch(self) -> dict[str, int | str]:
|
|
24
23
|
"""
|
|
25
24
|
Fetch Monzo credentials previously stored.
|
|
26
25
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Abstract class for credential storage."""
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
-
from typing import Dict, Union
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
class Storage(ABC):
|
|
@@ -13,7 +12,7 @@ class Storage(ABC):
|
|
|
13
12
|
"""
|
|
14
13
|
|
|
15
14
|
@abstractmethod
|
|
16
|
-
def fetch(self) ->
|
|
15
|
+
def fetch(self) -> dict[str, int | str]:
|
|
17
16
|
"""
|
|
18
17
|
Abstract method that needs to be implemented to Fetch Monzo credentials previously stored.
|
|
19
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Helper functions."""
|
|
2
2
|
|
|
3
|
-
from datetime import datetime
|
|
3
|
+
from datetime import UTC, datetime
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def create_date(date_str: str) -> datetime:
|
|
@@ -13,7 +13,7 @@ def create_date(date_str: str) -> datetime:
|
|
|
13
13
|
Returns:
|
|
14
14
|
Converted date and time
|
|
15
15
|
"""
|
|
16
|
-
return datetime.strptime(date_str[:19], "%Y-%m-%dT%H:%M:%S")
|
|
16
|
+
return datetime.strptime(date_str[:19], "%Y-%m-%dT%H:%M:%S").replace(tzinfo=UTC)
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def format_date(date: datetime) -> str:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Class that handles HTTP requests."""
|
|
2
2
|
|
|
3
3
|
from json import loads
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
from urllib.error import HTTPError
|
|
6
6
|
from urllib.parse import urlencode
|
|
7
7
|
from urllib.request import Request, urlopen
|
|
@@ -17,7 +17,7 @@ from monzo.exceptions import (
|
|
|
17
17
|
|
|
18
18
|
DEFAULT_TIMEOUT = 10
|
|
19
19
|
|
|
20
|
-
REQUEST_RESPONSE_TYPE =
|
|
20
|
+
REQUEST_RESPONSE_TYPE = dict[str, Any]
|
|
21
21
|
|
|
22
22
|
MONZO_ERROR_MAP = {
|
|
23
23
|
400: MonzoHTTPError,
|
|
@@ -32,7 +32,7 @@ MONZO_ERROR_MAP = {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
class HttpIO
|
|
35
|
+
class HttpIO:
|
|
36
36
|
"""
|
|
37
37
|
Class to facilitate http requests.
|
|
38
38
|
|
|
@@ -164,8 +164,8 @@ class HttpIO(object):
|
|
|
164
164
|
self,
|
|
165
165
|
method: str,
|
|
166
166
|
path: str,
|
|
167
|
-
data:
|
|
168
|
-
headers:
|
|
167
|
+
data: bytes | None,
|
|
168
|
+
headers: dict[str, Any],
|
|
169
169
|
timeout,
|
|
170
170
|
) -> REQUEST_RESPONSE_TYPE:
|
|
171
171
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "Monzo-API"
|
|
3
|
-
version = "1.2.
|
|
3
|
+
version = "1.2.7"
|
|
4
4
|
authors = [{ name = "Peter McDonald", email = "git@petermcdonald.co.uk"}]
|
|
5
5
|
description = "Package to interact with the API provided by Monzo bank"
|
|
6
6
|
keywords = ["monzo", "bank", "api"]
|
|
@@ -16,6 +16,7 @@ classifiers = [
|
|
|
16
16
|
"Programming Language :: Python :: 3.13",
|
|
17
17
|
"Programming Language :: Python :: 3.14",
|
|
18
18
|
"Programming Language :: Python :: 3.15",
|
|
19
|
+
"Programming Language :: Python :: 3.16",
|
|
19
20
|
"Topic :: Office/Business :: Financial",
|
|
20
21
|
"Typing :: Typed",
|
|
21
22
|
]
|
|
@@ -28,19 +29,11 @@ documentation = "https://monzo-api.readthedocs.io"
|
|
|
28
29
|
|
|
29
30
|
[dependency-groups]
|
|
30
31
|
dev = [
|
|
31
|
-
"cosmic-ray>=8.4.6",
|
|
32
|
-
"idna>=3.16", # To resolve security vulnerabilities in dependencies pip-audit
|
|
33
|
-
"pip-audit>=2.9.0",
|
|
34
|
-
"pygments>=2.20.0", # To resolve security vulnerabilities in dependencies pytest sphinx
|
|
35
32
|
"pytest>=9.0.3",
|
|
36
33
|
"pytest-cov>=7.1.0",
|
|
37
34
|
"pytest-mock>=3.15.1",
|
|
38
|
-
"ruff>=0.15.10",
|
|
39
35
|
"sphinx>=9.1.0",
|
|
40
36
|
"sphinx-rtd-theme>=3.1.0",
|
|
41
|
-
"troml>=0.4.1",
|
|
42
|
-
"ty>=0.0.29",
|
|
43
|
-
"urllib3>=2.7.0", # To resolve security vulnerabilities in dependencies pip-audit
|
|
44
37
|
]
|
|
45
38
|
|
|
46
39
|
[tool.pytest.ini_options]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Tests for endpoints."""
|
|
2
2
|
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from typing import Any
|
|
3
|
+
from datetime import UTC, datetime
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
import pytest
|
|
7
7
|
|
|
@@ -15,7 +15,7 @@ from monzo.endpoints.whoami import WhoAmI
|
|
|
15
15
|
from tests.helpers import Handler, load_data
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class TestEndPoints
|
|
18
|
+
class TestEndPoints:
|
|
19
19
|
"""Tests for the endpoints."""
|
|
20
20
|
|
|
21
21
|
@pytest.mark.parametrize(
|
|
@@ -146,8 +146,8 @@ class TestEndPoints(object):
|
|
|
146
146
|
expected_external_id: str,
|
|
147
147
|
expected_receipt_currency: str,
|
|
148
148
|
expected_receipt_merchant: MERCHANT_TYPE,
|
|
149
|
-
expected_receipt_payments:
|
|
150
|
-
expected_receipt_taxes:
|
|
149
|
+
expected_receipt_payments: list[PAYMENT_TYPE],
|
|
150
|
+
expected_receipt_taxes: list[TAX_TYPE],
|
|
151
151
|
expected_receipt_total: int,
|
|
152
152
|
expected_transaction_id: str,
|
|
153
153
|
mocker,
|
|
@@ -225,7 +225,7 @@ class TestEndPoints(object):
|
|
|
225
225
|
{"bills": -2775},
|
|
226
226
|
"bills",
|
|
227
227
|
{},
|
|
228
|
-
datetime(2022, 8, 9, 14, 15, 1),
|
|
228
|
+
datetime(year=2022, month=8, day=9, hour=14, minute=15, second=1, tzinfo=UTC),
|
|
229
229
|
"GBP",
|
|
230
230
|
"123ABC",
|
|
231
231
|
"",
|
|
@@ -250,9 +250,9 @@ class TestEndPoints(object):
|
|
|
250
250
|
"",
|
|
251
251
|
False,
|
|
252
252
|
"mastercard",
|
|
253
|
-
datetime(2022, 8, 10, 0, 30, 40),
|
|
253
|
+
datetime(year=2022, month=8, day=10, hour=0, minute=30, second=40, tzinfo=UTC),
|
|
254
254
|
"tx_123ABC1",
|
|
255
|
-
datetime(2022, 8, 10, 0, 30, 40),
|
|
255
|
+
datetime(year=2022, month=8, day=10, hour=0, minute=30, second=40, tzinfo=UTC),
|
|
256
256
|
"user_ABC123",
|
|
257
257
|
),
|
|
258
258
|
],
|
|
@@ -270,7 +270,7 @@ class TestEndPoints(object):
|
|
|
270
270
|
expected_can_be_made_subscription: bool,
|
|
271
271
|
expected_can_match_transactions_in_categorization: bool,
|
|
272
272
|
expected_can_split_the_bill: bool,
|
|
273
|
-
expected_categories:
|
|
273
|
+
expected_categories: dict[str, int | str],
|
|
274
274
|
expected_category: str,
|
|
275
275
|
expected_counterparty: str,
|
|
276
276
|
expected_created: datetime,
|
|
@@ -278,21 +278,21 @@ class TestEndPoints(object):
|
|
|
278
278
|
expected_dedupe_id: str,
|
|
279
279
|
expected_decline_reason: str,
|
|
280
280
|
expected_description: str,
|
|
281
|
-
expected_fees:
|
|
281
|
+
expected_fees: dict[str, Any],
|
|
282
282
|
expected_include_in_spending: bool,
|
|
283
|
-
expected_international:
|
|
283
|
+
expected_international: str | None,
|
|
284
284
|
expected_is_load: bool,
|
|
285
285
|
expected_labels: str,
|
|
286
286
|
expected_local_amount: int,
|
|
287
287
|
expected_local_currency: str,
|
|
288
288
|
expected_merchant: str,
|
|
289
|
-
expected_metadata:
|
|
289
|
+
expected_metadata: dict[str, str],
|
|
290
290
|
expected_notes: str,
|
|
291
291
|
expected_originator: bool,
|
|
292
292
|
expected_scheme: str,
|
|
293
|
-
expected_settled:
|
|
293
|
+
expected_settled: datetime | None,
|
|
294
294
|
expected_transaction_id: str,
|
|
295
|
-
expected_updated:
|
|
295
|
+
expected_updated: datetime | None,
|
|
296
296
|
expected_user_id: bool,
|
|
297
297
|
mocker,
|
|
298
298
|
):
|
|
@@ -358,7 +358,11 @@ class TestEndPoints(object):
|
|
|
358
358
|
|
|
359
359
|
auth.register_callback_handler(handler)
|
|
360
360
|
|
|
361
|
-
transactions = Transaction.fetch(
|
|
361
|
+
transactions = Transaction.fetch(
|
|
362
|
+
auth=auth,
|
|
363
|
+
account_id=expected_account_id,
|
|
364
|
+
since=datetime.now(tz=UTC),
|
|
365
|
+
)
|
|
362
366
|
assert len(transactions) == 1
|
|
363
367
|
transaction = transactions[0]
|
|
364
368
|
|
|
@@ -414,8 +418,8 @@ class TestEndPoints(object):
|
|
|
414
418
|
self,
|
|
415
419
|
mock_file: str,
|
|
416
420
|
expected_account_id: str,
|
|
417
|
-
expected_url:
|
|
418
|
-
expected_webhook_id:
|
|
421
|
+
expected_url: str | None,
|
|
422
|
+
expected_webhook_id: str | None,
|
|
419
423
|
expected_count: int,
|
|
420
424
|
mocker,
|
|
421
425
|
):
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from email.message import Message
|
|
1
2
|
from unittest.mock import patch
|
|
2
3
|
from urllib.error import HTTPError
|
|
3
4
|
|
|
@@ -5,12 +6,10 @@ import pytest
|
|
|
5
6
|
|
|
6
7
|
from monzo.exceptions import MonzoGeneralError
|
|
7
8
|
from monzo.httpio import HttpIO
|
|
8
|
-
from email.message import Message
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def test_unknown_status_code_raises_monzogeneralerror():
|
|
12
12
|
http = HttpIO("https://example.com")
|
|
13
13
|
error = HTTPError(url="https://example.com/test", code=418, msg="teapot", hdrs=Message(), fp=None)
|
|
14
|
-
with patch("monzo.httpio.urlopen", side_effect=error):
|
|
15
|
-
|
|
16
|
-
http.get("/test")
|
|
14
|
+
with patch("monzo.httpio.urlopen", side_effect=error), pytest.raises(MonzoGeneralError):
|
|
15
|
+
http.get("/test")
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Tests for HttpIO."""
|
|
2
2
|
|
|
3
3
|
from json import dumps
|
|
4
|
-
from typing import Dict
|
|
5
4
|
|
|
6
5
|
import pytest
|
|
7
6
|
|
|
@@ -16,7 +15,7 @@ from monzo.endpoints.whoami import WhoAmI
|
|
|
16
15
|
from tests.helpers import Handler, load_data
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
class TestHttpIO
|
|
18
|
+
class TestHttpIO:
|
|
20
19
|
"""Tests for the HttpIO class."""
|
|
21
20
|
|
|
22
21
|
@pytest.mark.parametrize(
|
|
@@ -54,7 +53,7 @@ class TestHttpIO(object):
|
|
|
54
53
|
http_method: str,
|
|
55
54
|
data_filename: str,
|
|
56
55
|
response_filename: str,
|
|
57
|
-
extra_data:
|
|
56
|
+
extra_data: dict[str, str],
|
|
58
57
|
mocker,
|
|
59
58
|
):
|
|
60
59
|
"""
|
|
@@ -194,7 +193,7 @@ class TestHttpIO(object):
|
|
|
194
193
|
http_method: str,
|
|
195
194
|
data_filename: str,
|
|
196
195
|
response_filename: str,
|
|
197
|
-
extra_data:
|
|
196
|
+
extra_data: dict[str, str],
|
|
198
197
|
mocker,
|
|
199
198
|
):
|
|
200
199
|
"""
|
|
@@ -258,7 +257,7 @@ class TestHttpIO(object):
|
|
|
258
257
|
http_method: str,
|
|
259
258
|
data_filename: str,
|
|
260
259
|
response_filename: str,
|
|
261
|
-
extra_data:
|
|
260
|
+
extra_data: dict[str, str],
|
|
262
261
|
mocker,
|
|
263
262
|
):
|
|
264
263
|
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|