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.
Files changed (41) hide show
  1. algopy/__init__.py +42 -0
  2. algopy/arc4.py +1 -0
  3. algopy/gtxn.py +1 -0
  4. algopy/itxn.py +1 -0
  5. algopy/op.py +1 -0
  6. algopy/py.typed +0 -0
  7. algopy_testing/__init__.py +47 -0
  8. algopy_testing/arc4.py +1222 -0
  9. algopy_testing/constants.py +17 -0
  10. algopy_testing/context.py +769 -0
  11. algopy_testing/decorators/__init__.py +0 -0
  12. algopy_testing/decorators/abimethod.py +146 -0
  13. algopy_testing/decorators/subroutine.py +9 -0
  14. algopy_testing/enums.py +39 -0
  15. algopy_testing/gtxn.py +239 -0
  16. algopy_testing/itxn.py +353 -0
  17. algopy_testing/models/__init__.py +23 -0
  18. algopy_testing/models/account.py +128 -0
  19. algopy_testing/models/application.py +72 -0
  20. algopy_testing/models/asset.py +109 -0
  21. algopy_testing/models/contract.py +69 -0
  22. algopy_testing/models/global_values.py +67 -0
  23. algopy_testing/models/gtxn.py +40 -0
  24. algopy_testing/models/itxn.py +34 -0
  25. algopy_testing/models/transactions.py +158 -0
  26. algopy_testing/models/txn.py +111 -0
  27. algopy_testing/models/unsigned_builtins.py +15 -0
  28. algopy_testing/op.py +639 -0
  29. algopy_testing/primitives/__init__.py +6 -0
  30. algopy_testing/primitives/biguint.py +147 -0
  31. algopy_testing/primitives/bytes.py +173 -0
  32. algopy_testing/primitives/string.py +67 -0
  33. algopy_testing/primitives/uint64.py +210 -0
  34. algopy_testing/py.typed +0 -0
  35. algopy_testing/state/__init__.py +4 -0
  36. algopy_testing/state/global_state.py +73 -0
  37. algopy_testing/state/local_state.py +54 -0
  38. algopy_testing/utils.py +156 -0
  39. algorand_python_testing-0.1.0.dist-info/METADATA +29 -0
  40. algorand_python_testing-0.1.0.dist-info/RECORD +41 -0
  41. algorand_python_testing-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,54 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+ from typing import TYPE_CHECKING
5
+
6
+ if TYPE_CHECKING:
7
+ import algopy
8
+
9
+ _T = typing.TypeVar("_T")
10
+
11
+
12
+ class LocalState(typing.Generic[_T]):
13
+ def __init__(
14
+ self,
15
+ type_: type[_T],
16
+ /,
17
+ *,
18
+ key: bytes | str = "",
19
+ description: str = "",
20
+ ) -> None:
21
+ self.type_ = type_
22
+ self.key = key
23
+ self.description = description
24
+ self._state: dict[object, _T] = {}
25
+
26
+ def _validate_local_state_key(self, key: algopy.Account | algopy.UInt64 | int) -> None:
27
+ from algopy import Account, UInt64
28
+
29
+ if not isinstance(key, Account | UInt64 | int):
30
+ raise TypeError(f"Invalid key type {type(key)} for LocalState")
31
+
32
+ def __setitem__(self, key: algopy.Account | algopy.UInt64 | int, value: _T) -> None:
33
+ self._validate_local_state_key(key)
34
+ self._state[key] = value
35
+
36
+ def __getitem__(self, key: algopy.Account | algopy.UInt64 | int) -> _T:
37
+ self._validate_local_state_key(key)
38
+ return self._state[key]
39
+
40
+ def __delitem__(self, key: algopy.Account | algopy.UInt64 | int) -> None:
41
+ self._validate_local_state_key(key)
42
+ del self._state[key]
43
+
44
+ def __contains__(self, key: algopy.Account | algopy.UInt64 | int) -> bool:
45
+ self._validate_local_state_key(key)
46
+ return key in self._state
47
+
48
+ def get(self, key: algopy.Account | algopy.UInt64 | int, default: _T | None = None) -> _T:
49
+ self._validate_local_state_key(key)
50
+ return self._state.get(key, default if default is not None else self.type_())
51
+
52
+ def maybe(self, key: algopy.Account | algopy.UInt64 | int) -> tuple[object, bool]:
53
+ self._validate_local_state_key(key)
54
+ return self._state.get(key), key in self._state
@@ -0,0 +1,156 @@
1
+ from __future__ import annotations
2
+
3
+ import enum
4
+ import functools
5
+ import secrets
6
+ from typing import TYPE_CHECKING
7
+
8
+ import algosdk
9
+ import algosdk.transaction
10
+
11
+ from algopy_testing import arc4
12
+ from algopy_testing.constants import MAX_BYTES_SIZE, MAX_UINT8, MAX_UINT16, MAX_UINT64, MAX_UINT512
13
+
14
+ if TYPE_CHECKING:
15
+ import algopy
16
+
17
+
18
+ def as_int(value: object, *, max: int | None) -> int: # noqa: A002
19
+ """
20
+ Returns the underlying int value for any numeric type up to UInt512
21
+
22
+ Raises:
23
+ TypeError: If `value` is not a numeric type
24
+ ValueError: If not 0 <= `value` <= max
25
+ """
26
+
27
+ from algopy_testing.primitives.biguint import BigUInt
28
+ from algopy_testing.primitives.uint64 import UInt64
29
+
30
+ match value:
31
+ case int(int_value):
32
+ pass
33
+ case UInt64(value=int_value):
34
+ pass
35
+ case BigUInt(value=int_value):
36
+ pass
37
+ case arc4.UIntN():
38
+ int_value = value.native.value
39
+ case arc4.BigUIntN():
40
+ int_value = value.native.value
41
+ # TODO: add arc4 numerics
42
+ case _:
43
+ raise TypeError(f"value must be a numeric type, not {type(value).__name__!r}")
44
+ if int_value < 0:
45
+ raise ValueError(f"expected positive value, got {int_value}")
46
+ if max is not None and int_value > max:
47
+ raise ValueError(f"expected value <= {max}, got: {int_value}")
48
+ return int_value
49
+
50
+
51
+ def as_int8(value: object) -> int:
52
+ return as_int(value, max=MAX_UINT8)
53
+
54
+
55
+ def as_int16(value: object) -> int:
56
+ return as_int(value, max=MAX_UINT16)
57
+
58
+
59
+ def as_int64(value: object) -> int:
60
+ return as_int(value, max=MAX_UINT64)
61
+
62
+
63
+ def as_int512(value: object) -> int:
64
+ return as_int(value, max=MAX_UINT512)
65
+
66
+
67
+ def as_bytes(value: object, *, max_size: int = MAX_BYTES_SIZE) -> bytes:
68
+ """
69
+ Returns the underlying bytes value for bytes or Bytes type up to 4096
70
+
71
+ Raises:
72
+ TypeError: If `value` is not a bytes type
73
+ ValueError: If not 0 <= `len(value)` <= max_size
74
+ """
75
+ from algopy_testing.primitives.bytes import Bytes
76
+
77
+ match value:
78
+ case bytes(bytes_value):
79
+ pass
80
+ case Bytes(value=bytes_value):
81
+ pass
82
+ case _:
83
+ raise TypeError(f"value must be a bytes or Bytes type, not {type(value).__name__!r}")
84
+ if len(bytes_value) > max_size:
85
+ raise ValueError(f"expected value length <= {max_size}, got: {len(bytes_value)}")
86
+ return bytes_value
87
+
88
+
89
+ def as_string(value: object) -> str:
90
+ from algopy_testing.primitives.string import String
91
+
92
+ match value:
93
+ case str(string_value) | String(value=string_value):
94
+ return string_value
95
+ case arc4.String():
96
+ return value.native.value
97
+ case _:
98
+ raise TypeError(f"value must be a string or String type, not {type(value).__name__!r}")
99
+
100
+
101
+ def int_to_bytes(x: int, pad_to: int | None = None) -> bytes:
102
+ result = x.to_bytes((x.bit_length() + 7) // 8, "big")
103
+ result = (
104
+ b"\x00" * (pad_to - len(result)) if pad_to is not None and len(result) < pad_to else b""
105
+ ) + result
106
+
107
+ return result
108
+
109
+
110
+ def dummy_transaction_id() -> bytes:
111
+ private_key, address = algosdk.account.generate_account()
112
+
113
+ suggested_params = algosdk.transaction.SuggestedParams(fee=1000, first=0, last=1, gh="")
114
+ txn = algosdk.transaction.PaymentTxn(
115
+ sender=address,
116
+ receiver=address,
117
+ amt=1000,
118
+ sp=suggested_params,
119
+ note=secrets.token_bytes(8),
120
+ )
121
+
122
+ signed_txn = txn.sign(private_key)
123
+ txn_id = str(signed_txn.transaction.get_txid()).encode("utf-8")
124
+ return txn_id
125
+
126
+
127
+ class _TransactionStrType(enum.StrEnum):
128
+ PAYMENT = algosdk.constants.PAYMENT_TXN
129
+ KEYREG = algosdk.constants.KEYREG_TXN
130
+ ASSETCONFIG = algosdk.constants.ASSETCONFIG_TXN
131
+ ASSETTRANSFER = algosdk.constants.ASSETTRANSFER_TXN
132
+ ASSETFREEZE = algosdk.constants.ASSETFREEZE_TXN
133
+ APPCALL = algosdk.constants.APPCALL_TXN
134
+
135
+
136
+ @functools.cache
137
+ def txn_type_to_bytes(txn_type: int) -> algopy.Bytes:
138
+ import algopy
139
+
140
+ match txn_type:
141
+ case algopy.TransactionType.Payment:
142
+ result = _TransactionStrType.PAYMENT
143
+ case algopy.TransactionType.KeyRegistration:
144
+ result = _TransactionStrType.KEYREG
145
+ case algopy.TransactionType.AssetConfig:
146
+ result = _TransactionStrType.ASSETCONFIG
147
+ case algopy.TransactionType.AssetTransfer:
148
+ result = _TransactionStrType.ASSETTRANSFER
149
+ case algopy.TransactionType.AssetFreeze:
150
+ result = _TransactionStrType.ASSETFREEZE
151
+ case algopy.TransactionType.ApplicationCall:
152
+ result = _TransactionStrType.APPCALL
153
+ case _:
154
+ raise ValueError(f"invalid transaction type: {txn_type}")
155
+
156
+ return algopy.Bytes(bytes(result, encoding="utf-8"))
@@ -0,0 +1,29 @@
1
+ Metadata-Version: 2.3
2
+ Name: algorand-python-testing
3
+ Version: 0.1.0
4
+ Summary: Algorand Python testing library
5
+ Project-URL: Documentation, https://github.com/algorandfoundation/puya/tree/main/algopy_testing#README.md
6
+ Project-URL: Issues, https://github.com/algorandfoundation/puya/issues
7
+ Project-URL: Source, https://github.com/algorandfoundation/puya/tree/main/algopy_testing
8
+ Author-email: Algorand Foundation <contact@algorand.foundation>
9
+ License-Expression: AGPL-3.0-or-later
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Topic :: Software Development :: Testing
15
+ Requires-Python: >=3.12
16
+ Requires-Dist: coincurve>=19.0.1
17
+ Requires-Dist: ecdsa>=0.17.0
18
+ Requires-Dist: pycryptodomex<4,>=3.6.0
19
+ Requires-Dist: pynacl<2,>=1.4.0
20
+ Requires-Dist: algorand-python>=1,<1.2.0
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Algorand Python Testing framework
24
+
25
+ Test your Algorand Python smart contracts using your favorite python testing tools.
26
+
27
+ ## Contributing
28
+
29
+ We welcome contributions to this project! Read the [contributing guide](CONTRIBUTING.md) to get started.
@@ -0,0 +1,41 @@
1
+ algopy/__init__.py,sha256=l4bTRdKBn9a1WnMtTTvpWYdm-FN_YdBZldEUWcIEBL8,792
2
+ algopy/arc4.py,sha256=zE-cwwmeEBA0m22QiHIujeY0S5rdyf3gDqTyGgROAqI,48
3
+ algopy/gtxn.py,sha256=tS2waKIr3g79T1xcmE2iVcvu524xANsR8awXduUVoT0,48
4
+ algopy/itxn.py,sha256=gXida1ee8xMfRufZ24G4xPGGSe26Iwm9nqfHpQCxbpE,48
5
+ algopy/op.py,sha256=JmF0QiVmqF1Oqhj9VypCl7ef-r2r-dHPI0hxIS3LQD8,46
6
+ algopy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ algopy_testing/__init__.py,sha256=MbIdz1mOyIpo_6smkfnT2BtHSZSm6TlVyLUxONLnyBQ,1018
8
+ algopy_testing/arc4.py,sha256=DJpZkHNkjGk23aReT_jzkd0U-RDlX3zoJ_MDnZOCRMM,41578
9
+ algopy_testing/constants.py,sha256=_LIk53HoJ_jRNMGMpU7hgd5WZEmz-G7OzwnTjGCpdwk,559
10
+ algopy_testing/context.py,sha256=oLZZ9vhWWkoEpeVD8JJb51IRLrCvF7_zYdkY1oXeYxE,24936
11
+ algopy_testing/enums.py,sha256=Vm2XG2-C2NpfMf8Pml908PydGOBWYawlu6P0N4nDX-g,565
12
+ algopy_testing/gtxn.py,sha256=90nZpNaYjeG7hJN0uCPZQ3_XkJRphlP_vXdtNt5VSrs,7119
13
+ algopy_testing/itxn.py,sha256=rDcUGleCiVkttv1k_0Cs03skbGZH_VnFE-1pNPjqgj8,11310
14
+ algopy_testing/op.py,sha256=OuZGLGumh66B3YZGpl6dJByf6WKRp6HFyZ3wsmMEUB8,18317
15
+ algopy_testing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ algopy_testing/utils.py,sha256=7Ril5VA_kGN3RrnnCjCb3HYeVV8T9bNxLm6pFL8uNMc,4795
17
+ algopy_testing/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ algopy_testing/decorators/abimethod.py,sha256=G1NzHSOb30LnorgtSdNqf1k7mFiSUGarJuYSOQIUoSE,4995
19
+ algopy_testing/decorators/subroutine.py,sha256=7bQt-RBdqmbzosMTIllBh1KCEDUSyZwNSxXc-1guflw,192
20
+ algopy_testing/models/__init__.py,sha256=dAUnsLdcIAKlsIp7CvIlOx3Xu9IRf6pm4pnTDTjIXX8,655
21
+ algopy_testing/models/account.py,sha256=vR_furAVjNGkT1x8vJ8BQeOuCyjg3Cwc1pIGUkwX-R0,4215
22
+ algopy_testing/models/application.py,sha256=H5WuY0gAfoTQE9glutAhKTfQs-iC4Nm7czmOpv-OqiQ,2205
23
+ algopy_testing/models/asset.py,sha256=qsvC7vGDKTH_PHqybc0SAgzPLAjPgzgwK0aDliUxoLk,3471
24
+ algopy_testing/models/contract.py,sha256=_jnw6FSiTQFsJlpqiqzLiH6_ct77cJk2dQs1MBO1IRw,1955
25
+ algopy_testing/models/global_values.py,sha256=Hz6Vv2-Mc5I_Om5KsUHVP2nQVmBKDNgwZFlNTrDdyJw,2045
26
+ algopy_testing/models/gtxn.py,sha256=nVsqmhnvRA4av2W2KRA7z5CXbrWOfpb2Mq-mifiXJnQ,1418
27
+ algopy_testing/models/itxn.py,sha256=MItNb6vMsXKxHctR-1_vb5m4vv16iflQu8sz-nR__5Y,1159
28
+ algopy_testing/models/transactions.py,sha256=_vMHFX8Nk6JYWOs3A-KkCjLfM8rsWM8BDAXuv_pZV7w,4313
29
+ algopy_testing/models/txn.py,sha256=ZSx_NKMwXaxqu4fUbwjD0r9Bktbnx8T8jLIlEwzg__4,3767
30
+ algopy_testing/models/unsigned_builtins.py,sha256=kXg1ylxwgTjpzzUnOQUK6I_kjlEvQzQ9MB6gWOd1PLo,261
31
+ algopy_testing/primitives/__init__.py,sha256=qwhRtTef1hp9d8OAcwkhKhGc-NuEhaNxUoTlLzJFXk0,260
32
+ algopy_testing/primitives/biguint.py,sha256=Ggnh5XwgCIFIb33Nwh1jvA9Kyn8nGBdk5cbFI41AS8M,5137
33
+ algopy_testing/primitives/bytes.py,sha256=3XEYGmo0fkSDcVOqU2f4E9BxJgYfpVJTynM5XeZzvgs,5633
34
+ algopy_testing/primitives/string.py,sha256=D3_QXXbHyrEbVjXIZ6L7Oo-kfKEbbOCAW461-UPnFuk,2127
35
+ algopy_testing/primitives/uint64.py,sha256=kteVN31IfNXAB-Ny8qgEq0ZaoxzgZ9GzQwQWZCFKwGE,7046
36
+ algopy_testing/state/__init__.py,sha256=uRFuGSn7RMnhjVKWWdHnVtPNhNfTlQIoQaDPbcmkr3U,155
37
+ algopy_testing/state/global_state.py,sha256=1eJRY9SYzOdj_dnNUqF_vghh0t9Q6N1B1MzLX0hKPxU,1662
38
+ algopy_testing/state/local_state.py,sha256=7m98XD5Afbn72yvgw9Q_VLAEhObLBv_5trp11ZkGwuE,1788
39
+ algorand_python_testing-0.1.0.dist-info/METADATA,sha256=I_qIAhhc679Y_E5R2OdVzeOQNjAjldHWYWGWiTxfgDU,1193
40
+ algorand_python_testing-0.1.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
41
+ algorand_python_testing-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.24.2
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any