Skip to content

Commit dd35e93

Browse files
committed
Merge branch 'master' into bilal/fix-release-config
2 parents 18899a9 + 6e1b32e commit dd35e93

File tree

5 files changed

+106
-42
lines changed

5 files changed

+106
-42
lines changed

method/resource.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,17 @@ def _make_request(self, method: str, path: Optional[str] = None, data: Optional[
160160
options = {}
161161
if data:
162162
options['data'] = json.dumps(data)
163+
# Note (Reza): Automatically appends '[]' to list-type query params (e.g., 'expand')
164+
# so users can pass them naturally without needing to format keys manually.
163165
if params:
164-
options['params'] = params
166+
fixed = {}
167+
for k, v in params.items():
168+
if isinstance(v, list):
169+
fixed[f"{k}[]"] = v
170+
else:
171+
fixed[k] = v
172+
options['params'] = fixed
173+
165174
if headers:
166175
options['headers'] = headers
167176

@@ -211,11 +220,11 @@ def _list(self, params: Optional[Dict] = None) -> MethodResponse[List[T]]:
211220
return self._make_request('GET', params=params)
212221

213222
@MethodError.catch
214-
def _create(self, data: Dict, request_opts: Optional[RequestOpts] = None) -> MethodResponse[T]:
223+
def _create(self, data: Dict, params: Optional[Dict] = None, request_opts: Optional[RequestOpts] = None) -> MethodResponse[T]:
215224
headers = {}
216225
if request_opts and request_opts.get('idempotency_key'):
217226
headers['Idempotency-Key'] = request_opts.get('idempotency_key')
218-
return self._make_request('POST', data=data, headers=headers)
227+
return self._make_request('POST', data=data, headers=headers, params=params)
219228

220229
@MethodError.catch
221230
def _create_with_sub_path(self, path: str, data: Dict) -> MethodResponse[T]:

method/resources/Entities/Connect.py

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,33 @@
66

77

88
EntityConnectResponseStatusLiterals = Literal[
9-
'completed',
10-
'in_progress',
11-
'pending',
12-
'failed'
9+
"completed", "in_progress", "pending", "failed"
10+
]
11+
12+
AccountConnectResponseExpandLiterals = Literal[
13+
"accounts",
14+
"accounts.sensitive",
15+
"accounts.balance",
16+
"accounts.card_brand",
17+
"accounts.attribute",
18+
"accounts.payoff",
19+
"accounts.transaction",
20+
"accounts.update",
21+
"accounts.payment_instrument",
22+
"accounts.latest_verification_session",
23+
]
24+
25+
AccountProductsEligibleForAutomaticExecutionLiteral = Literal[
26+
"account_attribute",
27+
"balance",
28+
"card_brand",
29+
"update",
30+
"payoff",
31+
]
32+
33+
34+
AccountSubscriptionsEligibleForAutomaticExecutionLiteral = Literal[
35+
"card_brand", "update", "update.snapshot", "transaction"
1336
]
1437

1538

@@ -22,15 +45,36 @@ class EntityConnect(TypedDict):
2245
updated_at: str
2346

2447

48+
class ConnectExpandOpts(TypedDict):
49+
expand: AccountConnectResponseExpandLiterals
50+
51+
52+
class ConnectResourceListOpts(ResourceListOpts, ConnectExpandOpts):
53+
pass
54+
55+
class ConnectCreateOpts(TypedDict):
56+
products: Optional[List[AccountProductsEligibleForAutomaticExecutionLiteral]]
57+
subscriptions: Optional[List[AccountSubscriptionsEligibleForAutomaticExecutionLiteral]]
58+
59+
60+
61+
2562
class EntityConnectResource(Resource):
2663
def __init__(self, config: Configuration):
27-
super(EntityConnectResource, self).__init__(config.add_path('connect'))
64+
super(EntityConnectResource, self).__init__(config.add_path("connect"))
2865

29-
def retrieve(self, cxn_id: str) -> MethodResponse[EntityConnect]:
30-
return super(EntityConnectResource, self)._get_with_id(cxn_id)
31-
32-
def list(self, params: Optional[ResourceListOpts] = None) -> MethodResponse[List[EntityConnect]]:
33-
return super(EntityConnectResource, self)._list(params)
66+
def retrieve(self, cxn_id: str, opts: Optional[ConnectExpandOpts] = None) -> MethodResponse[EntityConnect]:
67+
return super(EntityConnectResource, self)._get_with_sub_path_and_params(cxn_id, params=opts)
3468

35-
def create(self) -> MethodResponse[EntityConnect]:
36-
return super(EntityConnectResource, self)._create({})
69+
def list(
70+
self, opts: Optional[ConnectResourceListOpts] = None
71+
) -> MethodResponse[List[EntityConnect]]:
72+
return super(EntityConnectResource, self)._list(opts)
73+
74+
def create(
75+
self,
76+
opts: ConnectCreateOpts = {},
77+
params: Optional[ConnectExpandOpts] = None
78+
) -> MethodResponse[EntityConnect]:
79+
return super(EntityConnectResource, self)._create(data=opts, params=params)
80+

method/resources/Entities/Subscriptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import TypedDict, Optional, Literal, Dict, Any
1+
from typing import TypedDict, Optional, Literal, Dict, Any, Union
22

33
from method.resource import MethodResponse, Resource
44
from method.configuration import Configuration
@@ -54,7 +54,7 @@ def retrieve(self, sub_id: str) -> MethodResponse[EntitySubscriptionResponseOpts
5454
def list(self) -> MethodResponse[EntitySubscriptionListResponse]:
5555
return super(EntitySubscriptionsResource, self)._list()
5656

57-
def create(self, opts: EntitySubscriptionCreateOpts | EntitySubscriptionNamesLiterals) -> MethodResponse[EntitySubscriptionResponseOpts]:
57+
def create(self, opts: Union[EntitySubscriptionCreateOpts, EntitySubscriptionNamesLiterals]) -> MethodResponse[EntitySubscriptionResponseOpts]:
5858
if isinstance(opts, str):
5959
opts = {'enroll': opts}
6060
return super(EntitySubscriptionsResource, self)._create(opts)

test/resources/Account_test.py

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
from typing import List
33
import pytest
4+
import time
45
from method import Method
56
from dotenv import load_dotenv
67
from utils import await_results
@@ -300,7 +301,7 @@ def test_create_card_brands(setup):
300301
'id': card_brand_create_response['id'],
301302
'account_id': test_credit_card_account['id'],
302303
'network': 'visa',
303-
'status': 'completed',
304+
'status': 'in_progress',
304305
'issuer': card_brand_create_response['issuer'],
305306
'last4': '1580',
306307
'brands': card_brand_create_response['brands'],
@@ -311,52 +312,62 @@ def test_create_card_brands(setup):
311312
'updated_at': card_brand_create_response['updated_at'],
312313
}
313314

315+
time.sleep(5)
314316
assert card_brand_create_response == expect_results
315317

316318

317319
def test_retrieve_card_brands(setup):
318320
test_credit_card_account = setup['test_credit_card_account']
321+
319322
card_retrieve_response = method.accounts(test_credit_card_account['id']).card_brands.retrieve(card_brand_create_response['id'])
320323

321-
expect_results: AccountCardBrand = {
324+
expect_results = {
322325
'id': card_brand_create_response['id'],
323326
'account_id': test_credit_card_account['id'],
324327
'network': 'visa',
325328
'status': 'completed',
326329
'issuer': card_brand_create_response['issuer'],
327330
'last4': '1580',
328-
'brands': card_brand_create_response['brands'],
329331
'shared': False,
330-
'source': card_brand_create_response['source'],
332+
'source': "network",
331333
'error': None,
332334
'created_at': card_retrieve_response['created_at'],
333335
'updated_at': card_retrieve_response['updated_at'],
334336
}
335337

336-
assert card_retrieve_response == expect_results
338+
for k, v in expect_results.items():
339+
assert card_retrieve_response[k] == v
340+
341+
brand = card_retrieve_response['brands'][0]
342+
assert brand['id'] == 'brand_UBwVzXjpP4PJ6'
343+
assert brand['name'] == 'Chase Sapphire Reserve'
344+
assert brand['url'] == 'https://static.methodfi.com/card_brands/1b7ccaba6535cb837f802d968add4700.png'
345+
assert isinstance(brand['art_id'], str) and brand['art_id'].startswith('art_')
337346

338347
@pytest.mark.asyncio
339348
async def test_list_card_brands(setup):
340349
test_credit_card_account = setup['test_credit_card_account']
341-
342-
card_brands_list_response = method.accounts(test_credit_card_account['id']).card_brands.list()
343-
344-
expect_results: AccountCardBrand = {
345-
'id': card_brand_create_response['id'],
346-
'account_id': test_credit_card_account['id'],
347-
'network': 'visa',
348-
'status': 'completed',
349-
'issuer': card_brand_create_response['issuer'],
350-
'last4': '1580',
351-
'brands': card_brand_create_response['brands'],
352-
'shared': False,
353-
'source': card_brand_create_response['source'],
354-
'error': None,
355-
'created_at': card_brands_list_response[0]['created_at'],
356-
'updated_at': card_brands_list_response[0]['updated_at'],
357-
}
358350

359-
assert card_brands_list_response[0] == expect_results
351+
card_brands_list_response = method.accounts(test_credit_card_account['id']).card_brands.list()
352+
result = card_brands_list_response[0]
353+
354+
assert result['id'] == card_brand_create_response['id']
355+
assert result['account_id'] == test_credit_card_account['id']
356+
assert result['network'] == 'visa'
357+
assert result['status'] == 'completed'
358+
assert result['issuer'] == card_brand_create_response['issuer']
359+
assert result['last4'] == '1580'
360+
assert result['shared'] is False
361+
assert result['source'] == 'network'
362+
assert result['error'] is None
363+
assert result['created_at'] == result['created_at']
364+
assert result['updated_at'] == result['updated_at']
365+
366+
brand = result['brands'][0]
367+
assert brand['id'] == 'brand_UBwVzXjpP4PJ6'
368+
assert brand['name'] == 'Chase Sapphire Reserve'
369+
assert brand['url'] == 'https://static.methodfi.com/card_brands/1b7ccaba6535cb837f802d968add4700.png'
370+
assert isinstance(brand['art_id'], str) and brand['art_id'].startswith('art_')
360371

361372
def test_create_payoffs(setup):
362373
global payoff_create_response

test/resources/Report_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def test_create_report():
2525
"type": "payments.created.current",
2626
"url": f"https://dev.methodfi.com/reports/{report_create_response['id']}/download",
2727
"status": "completed",
28-
"metadata": None,
28+
"metadata": report_create_response["metadata"],
2929
"created_at": report_create_response["created_at"],
3030
"updated_at": report_create_response["updated_at"],
3131
}
@@ -43,7 +43,7 @@ def test_retrieve_report():
4343
"type": "payments.created.current",
4444
"url": f"https://dev.methodfi.com/reports/{report_create_response['id']}/download",
4545
"status": "completed",
46-
"metadata": None,
46+
"metadata": report_create_response["metadata"],
4747
"created_at": report_retrieve_response["created_at"],
4848
"updated_at": report_retrieve_response["updated_at"],
4949
}

0 commit comments

Comments
 (0)