algorand-python-testing 0.1.0__py3-none-any.whl
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.
- algopy/__init__.py +42 -0
- algopy/arc4.py +1 -0
- algopy/gtxn.py +1 -0
- algopy/itxn.py +1 -0
- algopy/op.py +1 -0
- algopy/py.typed +0 -0
- algopy_testing/__init__.py +47 -0
- algopy_testing/arc4.py +1222 -0
- algopy_testing/constants.py +17 -0
- algopy_testing/context.py +769 -0
- algopy_testing/decorators/__init__.py +0 -0
- algopy_testing/decorators/abimethod.py +146 -0
- algopy_testing/decorators/subroutine.py +9 -0
- algopy_testing/enums.py +39 -0
- algopy_testing/gtxn.py +239 -0
- algopy_testing/itxn.py +353 -0
- algopy_testing/models/__init__.py +23 -0
- algopy_testing/models/account.py +128 -0
- algopy_testing/models/application.py +72 -0
- algopy_testing/models/asset.py +109 -0
- algopy_testing/models/contract.py +69 -0
- algopy_testing/models/global_values.py +67 -0
- algopy_testing/models/gtxn.py +40 -0
- algopy_testing/models/itxn.py +34 -0
- algopy_testing/models/transactions.py +158 -0
- algopy_testing/models/txn.py +111 -0
- algopy_testing/models/unsigned_builtins.py +15 -0
- algopy_testing/op.py +639 -0
- algopy_testing/primitives/__init__.py +6 -0
- algopy_testing/primitives/biguint.py +147 -0
- algopy_testing/primitives/bytes.py +173 -0
- algopy_testing/primitives/string.py +67 -0
- algopy_testing/primitives/uint64.py +210 -0
- algopy_testing/py.typed +0 -0
- algopy_testing/state/__init__.py +4 -0
- algopy_testing/state/global_state.py +73 -0
- algopy_testing/state/local_state.py +54 -0
- algopy_testing/utils.py +156 -0
- algorand_python_testing-0.1.0.dist-info/METADATA +29 -0
- algorand_python_testing-0.1.0.dist-info/RECORD +41 -0
- algorand_python_testing-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import TYPE_CHECKING, Any, final
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
import algopy
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class StateTotals:
|
|
12
|
+
global_uints: int | None = None
|
|
13
|
+
global_bytes: int | None = None
|
|
14
|
+
local_uints: int | None = None
|
|
15
|
+
local_bytes: int | None = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class _ContractMeta(type):
|
|
19
|
+
def __call__(cls, *args: Any, **kwargs: dict[str, Any]) -> object:
|
|
20
|
+
from algopy import Contract
|
|
21
|
+
|
|
22
|
+
from algopy_testing.context import get_test_context
|
|
23
|
+
|
|
24
|
+
context = get_test_context()
|
|
25
|
+
instance = super().__call__(*args, **kwargs)
|
|
26
|
+
|
|
27
|
+
if context and isinstance(instance, Contract):
|
|
28
|
+
context._add_contract(instance)
|
|
29
|
+
|
|
30
|
+
return instance
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Contract(metaclass=_ContractMeta):
|
|
34
|
+
"""Base class for an Algorand Smart Contract"""
|
|
35
|
+
|
|
36
|
+
_name: str
|
|
37
|
+
_scratch_slots: Any | None
|
|
38
|
+
_state_totals: StateTotals | None
|
|
39
|
+
|
|
40
|
+
def __init_subclass__(
|
|
41
|
+
cls,
|
|
42
|
+
*,
|
|
43
|
+
name: str | None = None,
|
|
44
|
+
scratch_slots: (
|
|
45
|
+
algopy.UInt64 | tuple[int | algopy.UInt64, ...] | list[int | algopy.UInt64] | None
|
|
46
|
+
) = None,
|
|
47
|
+
state_totals: StateTotals | None = None,
|
|
48
|
+
):
|
|
49
|
+
cls._name = name or cls.__name__
|
|
50
|
+
cls._scratch_slots = scratch_slots
|
|
51
|
+
cls._state_totals = state_totals
|
|
52
|
+
|
|
53
|
+
def approval_program(self) -> algopy.UInt64 | bool:
|
|
54
|
+
raise NotImplementedError("`approval_program` is not implemented.")
|
|
55
|
+
|
|
56
|
+
def clear_state_program(self) -> algopy.UInt64 | bool:
|
|
57
|
+
raise NotImplementedError("`clear_state_program` is not implemented.")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ARC4Contract(Contract):
|
|
61
|
+
@final
|
|
62
|
+
def approval_program(self) -> algopy.UInt64 | bool:
|
|
63
|
+
raise NotImplementedError(
|
|
64
|
+
"`approval_program` is not implemented. To test ARC4 specific logic, "
|
|
65
|
+
"refer to direct calls to ARC4 methods."
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def clear_state_program(self) -> algopy.UInt64 | bool:
|
|
69
|
+
return True
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
import typing
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import TypedDict, TypeVar
|
|
7
|
+
|
|
8
|
+
if typing.TYPE_CHECKING:
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
|
|
11
|
+
import algopy
|
|
12
|
+
|
|
13
|
+
T = TypeVar("T")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class GlobalFields(TypedDict, total=False):
|
|
17
|
+
min_txn_fee: algopy.UInt64
|
|
18
|
+
min_balance: algopy.UInt64
|
|
19
|
+
max_txn_life: algopy.UInt64
|
|
20
|
+
zero_address: algopy.Account
|
|
21
|
+
group_size: algopy.UInt64
|
|
22
|
+
logic_sig_version: algopy.UInt64
|
|
23
|
+
round: algopy.UInt64
|
|
24
|
+
latest_timestamp: algopy.UInt64
|
|
25
|
+
current_application_id: algopy.UInt64
|
|
26
|
+
creator_address: algopy.Account
|
|
27
|
+
current_application_address: algopy.Account
|
|
28
|
+
group_id: algopy.Bytes
|
|
29
|
+
caller_application_id: algopy.Application
|
|
30
|
+
caller_application_address: algopy.Account
|
|
31
|
+
asset_create_min_balance: algopy.UInt64
|
|
32
|
+
asset_opt_in_min_balance: algopy.UInt64
|
|
33
|
+
genesis_hash: algopy.Bytes
|
|
34
|
+
opcode_budget: Callable[[], int]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class _Global:
|
|
39
|
+
def __getattr__(self, name: str) -> typing.Any:
|
|
40
|
+
from algopy import UInt64
|
|
41
|
+
|
|
42
|
+
from algopy_testing.context import get_test_context
|
|
43
|
+
|
|
44
|
+
context = get_test_context()
|
|
45
|
+
if not context:
|
|
46
|
+
raise ValueError(
|
|
47
|
+
"Test context is not initialized! Use `with algopy_testing_context()` to access "
|
|
48
|
+
"the context manager."
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if name == "latest_timestamp" and context._global_fields.get(name) is None:
|
|
52
|
+
return UInt64(int(time.time()))
|
|
53
|
+
|
|
54
|
+
if name == "group_size" and context._global_fields.get(name) is None:
|
|
55
|
+
return UInt64(len(context.get_transaction_group()))
|
|
56
|
+
|
|
57
|
+
if name not in context._global_fields:
|
|
58
|
+
raise AttributeError(
|
|
59
|
+
f"'algopy.Global' object has no value set for attribute named '{name}'. "
|
|
60
|
+
f"Use `context.patch_global_fields({name}=your_value)` to set the value "
|
|
61
|
+
"in your test setup."
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
return context._global_fields[name] # type: ignore[literal-required]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
Global = _Global()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class _GTxn:
|
|
6
|
+
def __getattr__(self, name: str) -> Callable[[int], typing.Any]:
|
|
7
|
+
from algopy_testing.context import get_test_context
|
|
8
|
+
|
|
9
|
+
context = get_test_context()
|
|
10
|
+
if not context:
|
|
11
|
+
raise ValueError(
|
|
12
|
+
"Test context is not initialized! Use `with algopy_testing_context()` to access "
|
|
13
|
+
"the context manager."
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
txn_group = context.get_transaction_group()
|
|
17
|
+
if not txn_group:
|
|
18
|
+
raise ValueError(
|
|
19
|
+
"No group transactions found in the context! Use `with algopy_testing_context()` "
|
|
20
|
+
"to access the context manager."
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
return lambda index: self._get_value(txn_group, name, index)
|
|
24
|
+
|
|
25
|
+
# TODO: refine mapping
|
|
26
|
+
def _map_fields(self, name: str) -> str:
|
|
27
|
+
field_mapping = {"type": "type_bytes", "type_enum": "type", "application_args": "app_args"}
|
|
28
|
+
return field_mapping.get(name, name)
|
|
29
|
+
|
|
30
|
+
def _get_value(self, txn_group: list[typing.Any], name: str, index: int) -> object:
|
|
31
|
+
if index >= len(txn_group):
|
|
32
|
+
raise IndexError("Transaction index out of range")
|
|
33
|
+
gtxn = txn_group[index]
|
|
34
|
+
value = getattr(gtxn, self._map_fields(name))
|
|
35
|
+
if value is None:
|
|
36
|
+
raise ValueError(f"'{name}' is not defined for {type(gtxn).__name__}")
|
|
37
|
+
return value
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
GTxn = _GTxn()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class _ITxn:
|
|
6
|
+
def __getattr__(self, name: str) -> Callable[[], typing.Any]:
|
|
7
|
+
from algopy_testing.context import get_test_context
|
|
8
|
+
|
|
9
|
+
context = get_test_context()
|
|
10
|
+
if not context:
|
|
11
|
+
raise ValueError(
|
|
12
|
+
"Test context is not initialized! Use `with algopy_testing_context()` to access "
|
|
13
|
+
"the context manager."
|
|
14
|
+
)
|
|
15
|
+
if not context._inner_transaction_groups:
|
|
16
|
+
raise ValueError(
|
|
17
|
+
"No inner transaction found in the context! Use `with algopy_testing_context()` "
|
|
18
|
+
"to access the context manager."
|
|
19
|
+
)
|
|
20
|
+
last_itxn_group = context._inner_transaction_groups[-1]
|
|
21
|
+
|
|
22
|
+
if not last_itxn_group:
|
|
23
|
+
raise ValueError("No inner transaction found in the testing context!")
|
|
24
|
+
|
|
25
|
+
last_itxn = last_itxn_group[-1]
|
|
26
|
+
|
|
27
|
+
value = getattr(last_itxn, name)
|
|
28
|
+
if value is None:
|
|
29
|
+
raise ValueError(f"'{name}' is not defined for {type(last_itxn).__name__} ")
|
|
30
|
+
# mimic the static functions on ITxn with a lambda
|
|
31
|
+
return lambda: value
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
ITxn = _ITxn()
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
from typing import TYPE_CHECKING, TypedDict
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
import algopy
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class _TransactionCoreFields(TypedDict, total=False):
|
|
11
|
+
sender: algopy.Account
|
|
12
|
+
fee: algopy.UInt64
|
|
13
|
+
first_valid: algopy.UInt64
|
|
14
|
+
first_valid_time: algopy.UInt64
|
|
15
|
+
last_valid: algopy.UInt64
|
|
16
|
+
note: algopy.Bytes
|
|
17
|
+
lease: algopy.Bytes
|
|
18
|
+
txn_id: algopy.Bytes
|
|
19
|
+
rekey_to: algopy.Account
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class _TransactionBaseFields(_TransactionCoreFields, total=False):
|
|
23
|
+
type: algopy.TransactionType
|
|
24
|
+
type_bytes: algopy.Bytes
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _AssetTransferBaseFields(TypedDict, total=False):
|
|
28
|
+
xfer_asset: algopy.Asset
|
|
29
|
+
asset_amount: algopy.UInt64
|
|
30
|
+
asset_sender: algopy.Account
|
|
31
|
+
asset_receiver: algopy.Account
|
|
32
|
+
asset_close_to: algopy.Account
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class _PaymentBaseFields(TypedDict, total=False):
|
|
36
|
+
receiver: algopy.Account
|
|
37
|
+
amount: algopy.UInt64
|
|
38
|
+
close_remainder_to: algopy.Account
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class _AssetFreezeBaseFields(TypedDict, total=False):
|
|
42
|
+
freeze_asset: algopy.Asset
|
|
43
|
+
freeze_account: algopy.Account
|
|
44
|
+
frozen: bool
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class _AssetConfigBaseFields(TypedDict, total=False):
|
|
48
|
+
config_asset: algopy.Asset
|
|
49
|
+
total: algopy.UInt64
|
|
50
|
+
decimals: algopy.UInt64
|
|
51
|
+
default_frozen: bool
|
|
52
|
+
unit_name: algopy.Bytes
|
|
53
|
+
asset_name: algopy.Bytes
|
|
54
|
+
url: algopy.Bytes
|
|
55
|
+
metadata_hash: algopy.Bytes
|
|
56
|
+
manager: algopy.Account
|
|
57
|
+
reserve: algopy.Account
|
|
58
|
+
freeze: algopy.Account
|
|
59
|
+
clawback: algopy.Account
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class _ApplicationCallCoreFields(TypedDict, total=False):
|
|
63
|
+
app_id: algopy.Application
|
|
64
|
+
on_completion: algopy.OnCompleteAction
|
|
65
|
+
num_app_args: algopy.UInt64
|
|
66
|
+
num_accounts: algopy.UInt64
|
|
67
|
+
approval_program: algopy.Bytes
|
|
68
|
+
clear_state_program: algopy.Bytes
|
|
69
|
+
num_assets: algopy.UInt64
|
|
70
|
+
num_apps: algopy.UInt64
|
|
71
|
+
global_num_uint: algopy.UInt64
|
|
72
|
+
global_num_bytes: algopy.UInt64
|
|
73
|
+
local_num_uint: algopy.UInt64
|
|
74
|
+
local_num_bytes: algopy.UInt64
|
|
75
|
+
extra_program_pages: algopy.UInt64
|
|
76
|
+
last_log: algopy.Bytes
|
|
77
|
+
num_approval_program_pages: algopy.UInt64
|
|
78
|
+
num_clear_state_program_pages: algopy.UInt64
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class _ApplicationCallBaseFields(_ApplicationCallCoreFields, total=False):
|
|
82
|
+
app_args: typing.Callable[[algopy.UInt64 | int], algopy.Bytes]
|
|
83
|
+
accounts: typing.Callable[[algopy.UInt64 | int], algopy.Account]
|
|
84
|
+
assets: typing.Callable[[algopy.UInt64 | int], algopy.Asset]
|
|
85
|
+
apps: typing.Callable[[algopy.UInt64 | int], algopy.Application]
|
|
86
|
+
approval_program_pages: typing.Callable[[algopy.UInt64 | int], algopy.Bytes]
|
|
87
|
+
clear_state_program_pages: typing.Callable[[algopy.UInt64 | int], algopy.Bytes]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class _ApplicationCallFields(_TransactionBaseFields, _ApplicationCallCoreFields, total=False):
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class _KeyRegistrationBaseFields(TypedDict, total=False):
|
|
95
|
+
vote_key: algopy.Bytes
|
|
96
|
+
selection_key: algopy.Bytes
|
|
97
|
+
vote_first: algopy.UInt64
|
|
98
|
+
vote_last: algopy.UInt64
|
|
99
|
+
vote_key_dilution: algopy.UInt64
|
|
100
|
+
non_participation: bool
|
|
101
|
+
state_proof_key: algopy.Bytes
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class _TransactionFields(
|
|
105
|
+
_TransactionBaseFields,
|
|
106
|
+
_PaymentBaseFields,
|
|
107
|
+
_KeyRegistrationBaseFields,
|
|
108
|
+
_AssetConfigBaseFields,
|
|
109
|
+
_AssetTransferBaseFields,
|
|
110
|
+
_AssetFreezeBaseFields,
|
|
111
|
+
_ApplicationCallBaseFields,
|
|
112
|
+
total=False,
|
|
113
|
+
):
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class AssetTransferFields(_TransactionBaseFields, _AssetTransferBaseFields, total=False):
|
|
118
|
+
pass
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class PaymentFields(_TransactionBaseFields, _PaymentBaseFields, total=False):
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class AssetFreezeFields(_TransactionBaseFields, _AssetFreezeBaseFields, total=False):
|
|
126
|
+
pass
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class AssetConfigFields(_TransactionBaseFields, _AssetConfigBaseFields, total=False):
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class ApplicationCallFields(_TransactionBaseFields, _ApplicationCallBaseFields, total=False):
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class KeyRegistrationFields(_TransactionBaseFields, _KeyRegistrationBaseFields, total=False):
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
__all__ = [
|
|
142
|
+
"_ApplicationCallBaseFields",
|
|
143
|
+
"_ApplicationCallFields",
|
|
144
|
+
"_AssetConfigBaseFields",
|
|
145
|
+
"_AssetFreezeBaseFields",
|
|
146
|
+
"_AssetTransferBaseFields",
|
|
147
|
+
"_KeyRegistrationBaseFields",
|
|
148
|
+
"_PaymentBaseFields",
|
|
149
|
+
"_TransactionBaseFields",
|
|
150
|
+
"_TransactionCoreFields",
|
|
151
|
+
"_TransactionFields",
|
|
152
|
+
"ApplicationCallFields",
|
|
153
|
+
"AssetConfigFields",
|
|
154
|
+
"AssetFreezeFields",
|
|
155
|
+
"AssetTransferFields",
|
|
156
|
+
"KeyRegistrationFields",
|
|
157
|
+
"PaymentFields",
|
|
158
|
+
]
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
from typing import TYPE_CHECKING, TypedDict, TypeVar
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
import algopy
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
T = TypeVar("T")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TxnFields(TypedDict, total=False):
|
|
14
|
+
sender: algopy.Account
|
|
15
|
+
fee: algopy.UInt64
|
|
16
|
+
first_valid: algopy.UInt64
|
|
17
|
+
first_valid_time: algopy.UInt64
|
|
18
|
+
last_valid: algopy.UInt64
|
|
19
|
+
note: algopy.Bytes
|
|
20
|
+
lease: algopy.Bytes
|
|
21
|
+
receiver: algopy.Account
|
|
22
|
+
amount: algopy.UInt64
|
|
23
|
+
close_remainder_to: algopy.Account
|
|
24
|
+
vote_pk: algopy.Bytes
|
|
25
|
+
selection_pk: algopy.Bytes
|
|
26
|
+
vote_first: algopy.UInt64
|
|
27
|
+
vote_last: algopy.UInt64
|
|
28
|
+
vote_key_dilution: algopy.UInt64
|
|
29
|
+
type: algopy.Bytes
|
|
30
|
+
type_enum: algopy.UInt64
|
|
31
|
+
xfer_asset: algopy.Asset
|
|
32
|
+
asset_amount: algopy.UInt64
|
|
33
|
+
asset_sender: algopy.Account
|
|
34
|
+
asset_receiver: algopy.Account
|
|
35
|
+
asset_close_to: algopy.Account
|
|
36
|
+
group_index: algopy.UInt64
|
|
37
|
+
tx_id: algopy.Bytes
|
|
38
|
+
application_id: algopy.Application
|
|
39
|
+
on_completion: algopy.UInt64
|
|
40
|
+
num_app_args: algopy.UInt64
|
|
41
|
+
num_accounts: algopy.UInt64
|
|
42
|
+
approval_program: algopy.Bytes
|
|
43
|
+
clear_state_program: algopy.Bytes
|
|
44
|
+
rekey_to: algopy.Account
|
|
45
|
+
config_asset: algopy.Asset
|
|
46
|
+
config_asset_total: algopy.UInt64
|
|
47
|
+
config_asset_decimals: algopy.UInt64
|
|
48
|
+
config_asset_default_frozen: bool
|
|
49
|
+
config_asset_unit_name: algopy.Bytes
|
|
50
|
+
config_asset_name: algopy.Bytes
|
|
51
|
+
config_asset_url: algopy.Bytes
|
|
52
|
+
config_asset_metadata_hash: algopy.Bytes
|
|
53
|
+
config_asset_manager: algopy.Account
|
|
54
|
+
config_asset_reserve: algopy.Account
|
|
55
|
+
config_asset_freeze: algopy.Account
|
|
56
|
+
config_asset_clawback: algopy.Account
|
|
57
|
+
freeze_asset: algopy.Asset
|
|
58
|
+
freeze_asset_account: algopy.Account
|
|
59
|
+
freeze_asset_frozen: bool
|
|
60
|
+
num_assets: algopy.UInt64
|
|
61
|
+
num_applications: algopy.UInt64
|
|
62
|
+
global_num_uint: algopy.UInt64
|
|
63
|
+
global_num_byte_slice: algopy.UInt64
|
|
64
|
+
local_num_uint: algopy.UInt64
|
|
65
|
+
local_num_byte_slice: algopy.UInt64
|
|
66
|
+
extra_program_pages: algopy.UInt64
|
|
67
|
+
nonparticipation: bool
|
|
68
|
+
num_logs: algopy.UInt64
|
|
69
|
+
created_asset_id: algopy.Asset
|
|
70
|
+
created_application_id: algopy.Application
|
|
71
|
+
last_log: algopy.Bytes
|
|
72
|
+
state_proof_pk: algopy.Bytes
|
|
73
|
+
num_approval_program_pages: algopy.UInt64
|
|
74
|
+
num_clear_state_program_pages: algopy.UInt64
|
|
75
|
+
application_args: tuple[algopy.Bytes, ...]
|
|
76
|
+
accounts: tuple[algopy.Account, ...]
|
|
77
|
+
assets: tuple[algopy.Asset, ...]
|
|
78
|
+
applications: tuple[algopy.Application, ...]
|
|
79
|
+
logs: tuple[algopy.Bytes, ...]
|
|
80
|
+
approval_program_pages: tuple[algopy.Bytes, ...]
|
|
81
|
+
clear_state_program_pages: tuple[algopy.Bytes, ...]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class _Txn:
|
|
85
|
+
def _map_fields(self, name: str) -> str:
|
|
86
|
+
field_mapping = {"type": "type_bytes", "type_enum": "type", "application_args": "app_args"}
|
|
87
|
+
return field_mapping.get(name, name)
|
|
88
|
+
|
|
89
|
+
def __getattr__(self, name: str) -> typing.Any:
|
|
90
|
+
from algopy_testing.context import get_test_context
|
|
91
|
+
|
|
92
|
+
context = get_test_context()
|
|
93
|
+
if not context:
|
|
94
|
+
raise ValueError(
|
|
95
|
+
"Test context is not initialized! Use `with algopy_testing_context()` to access "
|
|
96
|
+
"the context manager."
|
|
97
|
+
)
|
|
98
|
+
active_txn = context.get_active_transaction()
|
|
99
|
+
if name in context._txn_fields and context._txn_fields[name] is not None: # type: ignore[literal-required]
|
|
100
|
+
return context._txn_fields[name] # type: ignore[literal-required]
|
|
101
|
+
elif active_txn:
|
|
102
|
+
return getattr(active_txn, self._map_fields(name))
|
|
103
|
+
else:
|
|
104
|
+
raise AttributeError(
|
|
105
|
+
f"'Txn' object has no value set for attribute named '{name}'. "
|
|
106
|
+
f"Use `context.patch_txn_fields({name}=your_value)` to set the value "
|
|
107
|
+
"in your test setup."
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
Txn = _Txn()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
if typing.TYPE_CHECKING:
|
|
6
|
+
import algopy
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class urange: # noqa: N801
|
|
10
|
+
def __init__(self, *args: int | algopy.UInt64) -> None:
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def uenumerate(_iterable: typing.Any) -> typing.Any:
|
|
15
|
+
pass
|