Skip to content

Commit 5c4335b

Browse files
authored
Merge pull request #31 from algorandfoundation/chore/algokit-utils-v3
chore: utils-v3 support
2 parents 7b3fea8 + 0d1aedc commit 5c4335b

File tree

13 files changed

+202
-245
lines changed

13 files changed

+202
-245
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ dependencies = [
5757
"pytest-mock>=3.10.0",
5858
"pytest-xdist[psutil]>=3.3",
5959
"py-algorand-sdk>=2.4.0",
60-
"algokit-utils>=2.2.1",
60+
"algokit-utils>=3.0.0",
6161
"pytest-cov>=4.1.0",
6262
"prettytable>=3.9.0",
6363
"mypy==1.10",
@@ -171,7 +171,7 @@ dependencies = [
171171
"pytest-mock>=3.10.0",
172172
"pytest-xdist[psutil]>=3.3",
173173
"py-algorand-sdk>=2.4.0",
174-
"algokit-utils>=2.2.1",
174+
"algokit-utils>=3.0.0",
175175
"pytest-cov>=4.1.0",
176176
"mypy==1.10",
177177
]

src/_algopy_testing/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
__all__ = [
2929
"ARC4Contract",
3030
"ARC4ValueGenerator",
31+
"AVMValueGenerator",
3132
"Account",
3233
"AlgopyTestContext",
3334
"Application",
@@ -39,20 +40,19 @@
3940
"Bytes",
4041
"Contract",
4142
"GlobalState",
43+
"ITxnGroupLoader",
44+
"ITxnLoader",
45+
"LedgerContext",
4246
"LocalState",
4347
"LogicSig",
44-
"ITxnLoader",
45-
"TxnValueGenerator",
46-
"ITxnGroupLoader",
4748
"OnCompleteAction",
4849
"StateTotals",
4950
"String",
5051
"TemplateVar",
51-
"LedgerContext",
5252
"TransactionContext",
53-
"AVMValueGenerator",
54-
"TxnValueGenerator",
5553
"TransactionType",
54+
"TxnValueGenerator",
55+
"TxnValueGenerator",
5656
"UInt64",
5757
"algopy_testing_context",
5858
"arc4",

src/_algopy_testing/models/txn_fields.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,10 +508,10 @@ def wrapper(index: algopy.UInt64 | int) -> _T:
508508
"AssetConfigFields",
509509
"AssetFreezeFields",
510510
"AssetTransferFields",
511-
"TransactionFieldsGetter",
512511
"KeyRegistrationFields",
513512
"PaymentFields",
514513
"TransactionFields",
514+
"TransactionFieldsGetter",
515515
"get_txn_defaults",
516516
"narrow_field_type",
517517
]

src/algopy/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@
2222
from . import arc4, gtxn, itxn, op
2323

2424
__all__ = [
25+
"ARC4Contract",
2526
"Account",
2627
"Application",
27-
"ARC4Contract",
2828
"Asset",
2929
"BigUInt",
30+
"Box",
31+
"BoxMap",
32+
"BoxRef",
3033
"Bytes",
3134
"BytesBacked",
3235
"CompiledContract",
@@ -56,7 +59,4 @@
5659
"subroutine",
5760
"uenumerate",
5861
"urange",
59-
"Box",
60-
"BoxRef",
61-
"BoxMap",
6262
]

tests/arc4/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from pathlib import Path
22

33
import pytest
4-
from algosdk.v2client.algod import AlgodClient
4+
from algokit_utils import AlgorandClient
55

66
from tests.common import AVMInvoker, create_avm_invoker
77

@@ -10,5 +10,5 @@
1010

1111

1212
@pytest.fixture(scope="module")
13-
def get_avm_result(algod_client: AlgodClient) -> AVMInvoker:
14-
return create_avm_invoker(APP_SPEC, algod_client)
13+
def get_avm_result(algorand: AlgorandClient) -> AVMInvoker:
14+
return create_avm_invoker(APP_SPEC, algorand)

tests/arc4/test_arc4_method_signature.py

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
import algopy
77
import algosdk
88
import pytest
9-
from algokit_utils.beta.algorand_client import AlgorandClient, AssetCreateParams, PayParams
9+
from algokit_utils import AlgoAmount, AlgorandClient, AssetCreateParams, PaymentParams
1010
from algopy import arc4
1111
from algosdk.atomic_transaction_composer import TransactionWithSigner
12-
from algosdk.v2client.algod import AlgodClient
1312

1413
from tests.artifacts.Arc4ABIMethod.contract import (
1514
AnotherStruct,
@@ -25,8 +24,8 @@
2524

2625

2726
@pytest.fixture()
28-
def get_avm_result(algod_client: AlgodClient) -> AVMInvoker:
29-
return create_avm_invoker(APP_SPEC, algod_client)
27+
def get_avm_result(algorand: AlgorandClient) -> AVMInvoker:
28+
return create_avm_invoker(APP_SPEC, algorand)
3029

3130

3231
@pytest.fixture()
@@ -36,25 +35,22 @@ def context() -> Generator[_algopy_testing.AlgopyTestContext, None, None]:
3635

3736

3837
@pytest.fixture()
39-
def funded_account(algod_client: AlgodClient, context: _algopy_testing.AlgopyTestContext) -> str:
40-
pk, address = algosdk.account.generate_account()
41-
assert isinstance(address, str)
42-
algokit_utils.ensure_funded(
43-
algod_client,
44-
algokit_utils.EnsureBalanceParameters(
45-
account_to_fund=address,
46-
min_spending_balance_micro_algos=_FUNDED_ACCOUNT_SPENDING,
47-
),
38+
def funded_account(algorand: AlgorandClient, context: _algopy_testing.AlgopyTestContext) -> str:
39+
account = algorand.account.random()
40+
algorand.account.ensure_funded_from_environment(
41+
account_to_fund=account,
42+
min_spending_balance=algokit_utils.AlgoAmount(micro_algo=_FUNDED_ACCOUNT_SPENDING),
4843
)
49-
5044
# ensure context has the same account with matching balance
51-
context.any.account(address, balance=algopy.Global.min_balance + _FUNDED_ACCOUNT_SPENDING)
52-
return address
45+
context.any.account(
46+
account.address, balance=algopy.Global.min_balance + _FUNDED_ACCOUNT_SPENDING
47+
)
48+
return account.address
5349

5450

5551
@pytest.fixture()
56-
def other_app_id(algod_client: AlgodClient, context: _algopy_testing.AlgopyTestContext) -> int:
57-
second_invoker = create_avm_invoker(APP_SPEC, algod_client)
52+
def other_app_id(algorand: AlgorandClient, context: _algopy_testing.AlgopyTestContext) -> int:
53+
second_invoker = create_avm_invoker(APP_SPEC, algorand)
5854
client = second_invoker.client
5955
app_id = client.app_id
6056

@@ -127,14 +123,14 @@ def test_app_args_is_correct_with_txn(
127123
"with_txn",
128124
value="hello",
129125
pay=TransactionWithSigner(
130-
txn=algorand.transactions.payment(
131-
PayParams(
126+
txn=algorand.create_transaction.payment(
127+
PaymentParams(
132128
sender=localnet_creator_address,
133129
receiver=localnet_creator_address,
134-
amount=123,
130+
amount=AlgoAmount(micro_algo=123),
135131
)
136132
),
137-
signer=algorand.account.get_signer("default"),
133+
signer=algorand.account.get_signer(localnet_creator_address),
138134
),
139135
arr=[1, 2],
140136
)
@@ -169,7 +165,9 @@ def test_app_args_is_correct_with_asset(
169165
sender=localnet_creator_address,
170166
total=123,
171167
)
172-
)["confirmation"]["asset-index"]
168+
).confirmation[
169+
"asset-index"
170+
] # type: ignore[call-overload]
173171

174172
# act
175173
get_avm_result("with_asset", value="hello", asset=asa_id, arr=[1, 2])
@@ -333,14 +331,14 @@ def test_prepare_txns_with_complex(
333331
"complex_sig",
334332
struct1=((1, "2"), (1, "2"), 3, 4),
335333
txn=TransactionWithSigner(
336-
txn=algorand.transactions.payment(
337-
PayParams(
334+
txn=algorand.create_transaction.payment(
335+
PaymentParams(
338336
sender=localnet_creator_address,
339337
receiver=localnet_creator_address,
340-
amount=123,
338+
amount=AlgoAmount(micro_algo=123),
341339
)
342340
),
343-
signer=algorand.account.get_signer("default"),
341+
signer=algorand.account.get_signer(localnet_creator_address),
344342
),
345343
acc=funded_account,
346344
five=[5],

tests/common.py

Lines changed: 46 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66

77
import algosdk
88
from algokit_utils import (
9-
Account,
10-
ApplicationClient,
11-
EnsureBalanceParameters,
12-
ensure_funded,
13-
get_localnet_default_account,
9+
AlgorandClient,
10+
AppClient,
11+
AppClientMethodCallParams,
12+
AppFactory,
13+
AppFactoryCreateMethodCallParams,
14+
AppFactoryCreateParams,
15+
AppFactoryParams,
16+
SigningAccount,
1417
)
1518
from algosdk.v2client.algod import AlgodClient
1619

@@ -21,65 +24,70 @@ class AVMInvoker:
2124
"""Protocol used in global test fixtures to simplify invocation of AVM methods via an Algokit
2225
typed client."""
2326

24-
def __init__(self, client: ApplicationClient):
27+
def __init__(self, client: AppClient, factory: AppFactory):
2528
self.client = client
29+
self.factory = factory
2630

2731
def __call__(
2832
self,
2933
method: str,
3034
on_complete: algosdk.transaction.OnComplete = algosdk.transaction.OnComplete.NoOpOC,
3135
**kwargs: typing.Any,
3236
) -> object:
33-
response = self.client.call(
34-
method,
35-
transaction_parameters={
36-
# random note avoids duplicate txn if tests are running concurrently
37-
"note": _random_note(),
38-
"accounts": kwargs.pop("accounts", None),
39-
"foreign_apps": kwargs.pop("foreign_apps", None),
40-
"foreign_assets": kwargs.pop("foreign_assets", None),
41-
"suggested_params": kwargs.pop("suggested_params", None),
42-
"on_complete": on_complete,
43-
},
44-
**kwargs,
37+
response = self.client.send.call(
38+
AppClientMethodCallParams(
39+
method=method,
40+
note=_random_note(),
41+
account_references=kwargs.pop("accounts", None),
42+
app_references=kwargs.pop("foreign_apps", None),
43+
asset_references=kwargs.pop("foreign_assets", None),
44+
on_complete=on_complete,
45+
static_fee=kwargs.pop("static_fee", None),
46+
args=[item[1] for item in kwargs.items()],
47+
),
4548
)
46-
if response.decode_error:
47-
raise ValueError(response.decode_error)
48-
result = response.return_value
49-
if result is None:
50-
return response.tx_info.get("logs", None)
49+
if response.returns and len(response.returns) > 0 and response.returns[0].decode_error:
50+
raise ValueError(response.returns[0].decode_error)
51+
result = response.abi_return
52+
if result is None and response.returns and len(response.returns) > 0:
53+
assert response.returns[0].tx_info
54+
return response.returns[0].tx_info.get("logs", None)
5155
if isinstance(result, list) and all(
5256
isinstance(i, int) and i >= 0 and i <= 255 for i in result
5357
):
54-
return bytes(result)
58+
return bytes(result) # type: ignore[arg-type]
5559
return result
5660

5761

5862
def _random_note() -> bytes:
5963
return secrets.token_bytes(8)
6064

6165

62-
def create_avm_invoker(app_spec: Path, algod_client: AlgodClient) -> AVMInvoker:
63-
client = ApplicationClient(
64-
algod_client,
65-
app_spec,
66-
signer=get_localnet_default_account(algod_client),
67-
)
68-
69-
client.create(
70-
transaction_parameters={
71-
# random note avoids duplicate txn if tests are running concurrently
72-
"note": _random_note(),
73-
}
66+
def create_avm_invoker(app_spec: Path, algorand: AlgorandClient) -> AVMInvoker:
67+
dispenser = algorand.account.localnet_dispenser()
68+
factory = AppFactory(
69+
AppFactoryParams(
70+
algorand=algorand,
71+
app_spec=app_spec.read_text(),
72+
default_sender=dispenser.address,
73+
),
7474
)
75+
try:
76+
client, _ = factory.send.bare.create(
77+
AppFactoryCreateParams(note=_random_note()),
78+
)
79+
except Exception as __:
80+
client, _ = factory.send.create(
81+
AppFactoryCreateMethodCallParams(method="create", note=_random_note()),
82+
)
7583

76-
return AVMInvoker(client)
84+
return AVMInvoker(client, factory)
7785

7886

7987
def generate_test_asset( # noqa: PLR0913
8088
*,
8189
algod_client: AlgodClient,
82-
sender: Account,
90+
sender: SigningAccount,
8391
total: int | None = None,
8492
decimals: int = 0,
8593
default_frozen: bool = False,
@@ -134,18 +142,3 @@ def generate_test_asset( # noqa: PLR0913
134142
return ptx["asset-index"]
135143
else:
136144
raise ValueError("Unexpected response from pending_transaction_info")
137-
138-
139-
def generate_test_account(algod_client: AlgodClient) -> Account:
140-
raw_account = algosdk.account.generate_account()
141-
account = Account(private_key=raw_account[0], address=raw_account[1])
142-
143-
ensure_funded(
144-
algod_client,
145-
EnsureBalanceParameters(
146-
account_to_fund=account,
147-
min_spending_balance_micro_algos=INITIAL_BALANCE_MICRO_ALGOS,
148-
),
149-
)
150-
151-
return account

0 commit comments

Comments
 (0)