Skip to content

Commit 1c77ad8

Browse files
authored
feat: TransactionComposer & AppManager implementation; various ongoing refactoring efforts (#120)
* feat: Initial AppManager implementation; wip on Composer; mypy tweaks; initial tests - Add AppManager class with methods for compiling TEAL, managing app state, and handling template variables - Update TransactionComposer to use AppManager - Move Account model to a separate file and update imports - Add new models for ABI values and application constants - Improve type annotations and remove unnecessary type ignores - Add initial tests for AppManager template substitution and comment stripping - Update mypy configuration to *globally* exclude untyped calls in algosdk -> removing ~50 individual mypy type ignore for algosdk * chore: removing models.py folders in favour of granular modules in root models namespace * chore: wip * feat: initial implementation of TransactionComposer
1 parent 9389170 commit 1c77ad8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2328
-592
lines changed

legacy_v2_tests/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,11 @@ def generate_test_asset(algod_client: "AlgodClient", sender: Account, total: int
188188
note=None,
189189
lease=None,
190190
rekey_to=None,
191-
) # type: ignore[no-untyped-call]
191+
)
192192

193-
signed_transaction = txn.sign(sender.private_key) # type: ignore[no-untyped-call]
193+
signed_transaction = txn.sign(sender.private_key)
194194
algod_client.send_transaction(signed_transaction)
195-
ptx = algod_client.pending_transaction_info(txn.get_txid()) # type: ignore[no-untyped-call]
195+
ptx = algod_client.pending_transaction_info(txn.get_txid())
196196

197197
if isinstance(ptx, dict) and "asset-index" in ptx and isinstance(ptx["asset-index"], int):
198198
return ptx["asset-index"]

pyproject.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ suppress-none-returning = true
125125
[tool.ruff.lint.per-file-ignores]
126126
"src/algokit_utils/beta/*" = ["ERA001", "E501", "PLR0911"]
127127
"path/to/file.py" = ["E402"]
128+
"tests/clients/test_algorand_client.py" = ["ERA001"]
128129

129130
[tool.poe.tasks]
130131
docs = ["docs-html-only", "docs-md-only"]
@@ -149,6 +150,14 @@ disallow_any_generics = false
149150
implicit_reexport = false
150151
show_error_codes = true
151152

153+
untyped_calls_exclude = [
154+
"algosdk",
155+
]
156+
157+
[[tool.mypy.overrides]]
158+
module = ["algosdk", "algosdk.*"]
159+
disallow_untyped_calls = false
160+
152161
[tool.semantic_release]
153162
version_toml = "pyproject.toml:tool.poetry.version"
154163
remove_dist = false

src/algokit_utils/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@
3030
from algokit_utils._legacy_v2.asset import opt_in, opt_out
3131
from algokit_utils._legacy_v2.common import Program
3232
from algokit_utils._legacy_v2.deploy import (
33-
DELETABLE_TEMPLATE_NAME,
3433
NOTE_PREFIX,
35-
UPDATABLE_TEMPLATE_NAME,
3634
ABICallArgs,
3735
ABICallArgsDict,
3836
ABICreateCallArgs,
@@ -61,7 +59,6 @@
6159
ABIArgsDict,
6260
ABIMethod,
6361
ABITransactionResponse,
64-
Account,
6562
CommonCallParameters,
6663
CommonCallParametersDict,
6764
CreateCallParameters,
@@ -91,6 +88,8 @@
9188
DispenserLimitResponse,
9289
TestNetDispenserApiClient,
9390
)
91+
from algokit_utils.models.account import Account
92+
from algokit_utils.models.application import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
9493

9594
__all__ = [
9695
# ==== LEGACY V2 EXPORTS BEGIN ====

src/algokit_utils/_debugging.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,7 @@ def _build_avm_sourcemap( # noqa: PLR0913
157157
raise ValueError("Either raw teal or compiled teal must be provided")
158158

159159
result = compiled_teal if compiled_teal else Program(str(raw_teal), client=client)
160-
program_hash = base64.b64encode(
161-
checksum(result.raw_binary) # type: ignore[no-untyped-call]
162-
).decode()
160+
program_hash = base64.b64encode(checksum(result.raw_binary)).decode()
163161
source_map = result.source_map.__dict__
164162
source_map["sources"] = [f"{file_name}{TEAL_FILE_EXT}"] if with_sources else []
165163

src/algokit_utils/_legacy_v2/_ensure_funded.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77

88
from algokit_utils._legacy_v2._transfer import TransferParameters, transfer
99
from algokit_utils._legacy_v2.account import get_dispenser_account
10-
from algokit_utils._legacy_v2.models import Account
1110
from algokit_utils._legacy_v2.network_clients import is_testnet
1211
from algokit_utils.clients.dispenser_api_client import (
1312
DispenserAssetName,
1413
TestNetDispenserApiClient,
1514
)
15+
from algokit_utils.models.account import Account
1616

1717

1818
@dataclass(kw_only=True)
@@ -63,7 +63,7 @@ def _get_address_to_fund(parameters: EnsureBalanceParameters) -> str:
6363
if isinstance(parameters.account_to_fund, str):
6464
return parameters.account_to_fund
6565
else:
66-
return str(address_from_private_key(parameters.account_to_fund.private_key)) # type: ignore[no-untyped-call]
66+
return str(address_from_private_key(parameters.account_to_fund.private_key))
6767

6868

6969
def _get_account_info(client: AlgodClient, address_to_fund: str) -> dict:
@@ -111,7 +111,7 @@ def _fund_using_transfer(
111111
fee_micro_algos=parameters.fee_micro_algos,
112112
),
113113
)
114-
transaction_id = response.get_txid() # type: ignore[no-untyped-call]
114+
transaction_id = response.get_txid()
115115
return EnsureFundedResponse(transaction_id=transaction_id, amount=response.amt)
116116

117117

src/algokit_utils/_legacy_v2/_transfer.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from algosdk.atomic_transaction_composer import AccountTransactionSigner
88
from algosdk.transaction import AssetTransferTxn, PaymentTxn, SuggestedParams
99

10-
from algokit_utils._legacy_v2.models import Account
10+
from algokit_utils.models.account import Account
1111

1212
if TYPE_CHECKING:
1313
from algosdk.v2client.algod import AlgodClient
@@ -93,7 +93,7 @@ def transfer(client: "AlgodClient", parameters: TransferParameters) -> PaymentTx
9393
amt=params.micro_algos,
9494
note=params.note.encode("utf-8") if isinstance(params.note, str) else params.note,
9595
sp=params.suggested_params,
96-
) # type: ignore[no-untyped-call]
96+
)
9797

9898
result = _send_transaction(client=client, transaction=transaction, parameters=params)
9999
assert isinstance(result, PaymentTxn)
@@ -117,7 +117,7 @@ def transfer_asset(client: "AlgodClient", parameters: TransferAssetParameters) -
117117
note=params.note,
118118
index=params.asset_id,
119119
rekey_to=None,
120-
) # type: ignore[no-untyped-call]
120+
)
121121

122122
result = _send_transaction(client=client, transaction=xfer_txn, parameters=params)
123123
assert isinstance(result, AssetTransferTxn)
@@ -148,5 +148,5 @@ def _get_address(account: Account | AccountTransactionSigner) -> str:
148148
if type(account) is Account:
149149
return account.address
150150
else:
151-
address = address_from_private_key(account.private_key) # type: ignore[no-untyped-call]
151+
address = address_from_private_key(account.private_key)
152152
return str(address)

src/algokit_utils/_legacy_v2/account.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
from algosdk.util import algos_to_microalgos
88

99
from algokit_utils._legacy_v2._transfer import TransferParameters, transfer
10-
from algokit_utils._legacy_v2.models import Account
1110
from algokit_utils._legacy_v2.network_clients import get_kmd_client_from_algod_client, is_localnet
11+
from algokit_utils.models.account import Account
1212

1313
if TYPE_CHECKING:
1414
from collections.abc import Callable
@@ -32,8 +32,8 @@
3232

3333
def get_account_from_mnemonic(mnemonic: str) -> Account:
3434
"""Convert a mnemonic (25 word passphrase) into an Account"""
35-
private_key = to_private_key(mnemonic) # type: ignore[no-untyped-call]
36-
address = address_from_private_key(private_key) # type: ignore[no-untyped-call]
35+
private_key = to_private_key(mnemonic)
36+
address = address_from_private_key(private_key)
3737
return Account(private_key=private_key, address=address)
3838

3939

@@ -47,7 +47,7 @@ def create_kmd_wallet_account(kmd_client: "KMDClient", name: str) -> Account:
4747
account_key = key_ids[0]
4848

4949
private_account_key = kmd_client.export_key(wallet_handle, "", account_key)
50-
return get_account_from_mnemonic(from_private_key(private_account_key)) # type: ignore[no-untyped-call]
50+
return get_account_from_mnemonic(from_private_key(private_account_key))
5151

5252

5353
def get_or_create_kmd_wallet_account(
@@ -79,7 +79,7 @@ def get_or_create_kmd_wallet_account(
7979
TransferParameters(
8080
from_account=get_dispenser_account(client),
8181
to_address=account.address,
82-
micro_algos=algos_to_microalgos(fund_with_algos), # type: ignore[no-untyped-call]
82+
micro_algos=algos_to_microalgos(fund_with_algos),
8383
),
8484
)
8585

@@ -139,7 +139,7 @@ def get_kmd_wallet_account(
139139
return None
140140

141141
private_account_key = kmd_client.export_key(wallet_handle, "", matched_account_key)
142-
return get_account_from_mnemonic(from_private_key(private_account_key)) # type: ignore[no-untyped-call]
142+
return get_account_from_mnemonic(from_private_key(private_account_key))
143143

144144

145145
def get_account(
@@ -177,7 +177,7 @@ def get_account(
177177

178178
if is_localnet(client):
179179
account = get_or_create_kmd_wallet_account(client, name, fund_with_algos, kmd_client)
180-
os.environ[mnemonic_key] = from_private_key(account.private_key) # type: ignore[no-untyped-call]
180+
os.environ[mnemonic_key] = from_private_key(account.private_key)
181181
return account
182182

183183
raise Exception(f"Missing environment variable '{mnemonic_key}' when looking for account '{name}'")

src/algokit_utils/_legacy_v2/application_client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
ABIArgType,
4444
ABIMethod,
4545
ABITransactionResponse,
46-
Account,
4746
CreateCallParameters,
4847
CreateCallParametersDict,
4948
OnCompleteCallParameters,
@@ -54,6 +53,7 @@
5453
TransactionResponse,
5554
)
5655
from algokit_utils.config import config
56+
from algokit_utils.models.account import Account
5757

5858
if typing.TYPE_CHECKING:
5959
from algosdk.v2client.algod import AlgodClient
@@ -1021,7 +1021,7 @@ def add_method_call( # noqa: PLR0913
10211021
raise Exception(f"ABI arguments specified on a bare call: {', '.join(abi_args)}")
10221022
atc.add_transaction(
10231023
TransactionWithSigner(
1024-
txn=transaction.ApplicationCallTxn( # type: ignore[no-untyped-call]
1024+
txn=transaction.ApplicationCallTxn(
10251025
sender=sender,
10261026
sp=sp,
10271027
index=app_id,
@@ -1329,11 +1329,11 @@ def get_sender_from_signer(signer: TransactionSigner | None) -> str | None:
13291329
"""Returns the associated address of a signer, return None if no address found"""
13301330

13311331
if isinstance(signer, AccountTransactionSigner):
1332-
sender = address_from_private_key(signer.private_key) # type: ignore[no-untyped-call]
1332+
sender = address_from_private_key(signer.private_key)
13331333
assert isinstance(sender, str)
13341334
return sender
13351335
elif isinstance(signer, MultisigTransactionSigner):
1336-
sender = signer.msig.address() # type: ignore[no-untyped-call]
1336+
sender = signer.msig.address()
13371337
assert isinstance(sender, str)
13381338
return sender
13391339
elif isinstance(signer, LogicSigTransactionSigner):

src/algokit_utils/_legacy_v2/application_specification.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def _encode_state_schema(schema: StateSchema) -> dict[str, int]:
130130

131131

132132
def _decode_state_schema(data: dict[str, int]) -> StateSchema:
133-
return StateSchema( # type: ignore[no-untyped-call]
133+
return StateSchema(
134134
num_byte_slices=data.get("num_byte_slices", 0),
135135
num_uints=data.get("num_uints", 0),
136136
)
@@ -203,4 +203,4 @@ def export(self, directory: Path | str | None = None) -> None:
203203

204204

205205
def _state_schema(schema: dict[str, int]) -> StateSchema:
206-
return StateSchema(schema.get("num-uint", 0), schema.get("num-byte-slice", 0)) # type: ignore[no-untyped-call]
206+
return StateSchema(schema.get("num-uint", 0), schema.get("num-byte-slice", 0))

src/algokit_utils/_legacy_v2/asset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from enum import Enum, auto
1212

13-
from algokit_utils._legacy_v2.models import Account
13+
from algokit_utils.models.account import Account
1414

1515
__all__ = ["opt_in", "opt_out"]
1616
logger = logging.getLogger(__name__)

0 commit comments

Comments
 (0)