Skip to content

Commit 1bb2366

Browse files
feat!: Account model refinements and further alignment with ts variant (#227)
* refactor: algod and api generator refinements aligning with ts * chore: txnleases * feat: default value handling of required fields; omitting txn leases field * fix(api): refine format parameter handling in client generator template - Only set format=msgpack when msgpack is explicitly selected - Remove unnecessary format=json assignments for JSON-only endpoints - Align with TypeScript client behavior * fix(api): regenerate algod client with refined format handling Generated output from updated client.py.j2 template: - Remove format=json for endpoints that only support JSON - Simplify msgpack format selection logic - Reduce unnecessary query parameters * fix(serde): handle dataclass fields that shadow builtin names When dataclasses use slots=True and have fields named 'bytes' or 'type', the class namespace contains member descriptors that interfere with get_type_hints() evaluation. Fix by passing explicit globalns with builtins and empty localns to get_type_hints() to avoid the class namespace pollution. Fixes TypeError: unsupported operand type(s) for |: 'member_descriptor' and 'NoneType' * fix(algod): make LedgerAppParams schema fields optional The local_state_schema and global_state_schema fields may not always be present in wire data from the ledger state delta endpoint. Make them optional with default=None to handle missing fields gracefully. * feat(test): integrate polytest mock server for API client testing Add Docker container-based mock server fixtures using testcontainers: - MockServerContainer class to manage PollyJS mock server lifecycle - Session-scoped fixtures for algod, indexer, and kmd mock servers - Mock server replays pre-recorded HAR files for deterministic testing - Fixtures automatically start/stop containers per test session - Configure via POLYTEST_MOCK_SERVER_IMAGE and POLYTEST_RECORDINGS_PATH env vars - Add test configuration constants matching TS mock server config * build: add testcontainers dependency and polytest poe tasks - Add testcontainers>=4.0.0 to dev dependencies for mock server containers - Add polytest generate/validate tasks for algod, indexer, kmd clients - Update transact polytest config to use algorandfoundation repo - Add polytest-generate-all and polytest-validate-all aggregate tasks - Add group_common_tests pytest marker for polytest test groups * ci: add polytest validation to check-python workflow - Install Rust toolchain and polytest CLI - Run polytest-validate-algod to ensure test structure matches polytest config - Validates that generated test files follow the expected naming conventions * refactor(test): move manual algod tests to dedicated folder Move manually written tests to tests/modules/algod_client/manual/ to distinguish them from polytest-generated test stubs: - test_block.py - test_ledger_state_delta.py - test_pending_transaction_information.py - test_raw_transaction.py - test_simulate_transactions.py - test_suggested_params.py Also fix localnet tests to use AlgorandClient.default_localnet().client.algod consistently instead of mixing mock server with localnet transactions. * test(algod): generate polytest stubs for all algod client endpoints Add NOT IMPLEMENTED test stubs for algod client API endpoints: - DELETE endpoints (catchup, ledger_sync) - GET endpoints (boxes, state proofs, deltas, devmode, experimental, etc.) - POST endpoints (catchup, ledger_sync, shutdown, teal, transactions) All stubs are marked with @pytest.mark.skip(reason='Test not implemented') and follow the polytest naming convention matching TypeScript tests. These stubs serve as placeholders for future test implementation and ensure structural parity with algokit-utils-ts polytest suite. * test(algod): implement polytest stubs aligning with TypeScript tests - Implement test_get_genesis.py, test_get_health.py, test_get_versions.py - Implement test_get_v2_status.py, test_get_v2_ledger_supply.py - Implement test_get_v2_transactions_params.py - Implement test_get_v2_accounts_address.py with localnet - Implement test_get_v2_blocks_round.py with mainnet/testnet endpoints - Implement test_get_v2_deltas_round.py with mainnet endpoint - Skip msgpack-related tests matching TypeScript approach - All tests verify client methods return correct model types * fix(test): move integration tests to manual folders and fix lint ignores - Move indexer and kmd integration tests to manual/ folders - These tests require localnet with indexer/kmd, not mock server - Update tests to use localnet clients directly - Add E501, W292, I001 lint ignores for tests/modules/**/* in pyproject.toml - Fix trailing newlines in polytest stub files (pre-commit format) * style: fix indentation in oas-generator template renderer * chore: update api client to support latest refined specs with inline duplicate schemas removed * chore: refine fixtures for cross worker access to mock server with filelock dependency * feat: add graceful handling of unknown transaction types * refactor: ensure models that are not used anywhere and/or are referenced by filtered oas tags are not generated * chore: extra fixes for unknown txn support * chore: adding snapshot testing; migration notes * chore: remove refs * chore: linter tweaks * chore: sqlite as default value from spec; retry mechanism for generated clients; minor alignment with latest on ts * feat: support fetching oas specs directly from oas-generator repo * chore: integrate docker image from fork; shared action * chore: temporarily comment out polytest validate in ci * docs: regen docs * chore: regen clients * chore: regen kmd clients; simplify remote oas fetching * chore: refine mock server fixtures * chore: refine pre commit; fix mypy warnings * chore: add jitter and polling health check to the mock server fixture * docs: remove mentions of oas shorthand * test: add indexer client polytest tests (#225) * test: add indexer client polytest tests - Add 21 indexer client endpoint tests aligned with TypeScript implementation - Add test constants for indexer test data (address, app_id, asset_id, txid, round) - Add JSON snapshots for all indexer endpoints - Tests use mock server recordings for deterministic testing * test: add KMD client polytest tests (#224) - Add 23 KMD client endpoint tests aligned with TypeScript implementation - Fix init_wallet_handle method name in kmd_account_manager.py - Fix manual test_key_management.py (remove non-existent display_mnemonic param) - Add JSON snapshots for KMD endpoints with recordings - Most tests skipped due to missing mock server recordings (require localnet) * chore: add support for overriding mock server urls for local dev * docs: update migration guide * chore: refresh kmd client * chore: refresh docs * feat: add support for skip tag in oas generator; dropping dryrun * chore: update branch for oas generator remote source to main * chore: further simplify mock server * chore: wip aligning with ts account model refinements * refactor: adds MX domain separation for arbitrary bytes signing * refactor: decouples signing from algokit-algosdk * refactor: remove backward compatibility for LogicSigAccount and deprecate TransactionSignerAccount BREAKING CHANGES: - Remove LogicSigAccount.lsig property (algosdk compatibility) - Remove LogicSigAccount.algokit_lsig property - Deprecate TransactionSignerAccount class (use TransactionSignerAccountProtocol) - AccountManager.rekeyed() now returns TransactionSignerAccountProtocol instead of TransactionSignerAccount Aligns with TypeScript PR #465 which removes backward compatibility for secretless signing architecture. * feat!: align signing abstractions with algokit-utils-ts PR #465 Refactors account and signing abstractions to match TypeScript naming conventions and adds missing functionality for feature parity. ## Breaking Changes - `MultiSigAccount` renamed to `MultisigAccount` - `signing_accounts` parameter/property renamed to `sub_signers` - `HasAddress` protocol renamed to `Addressable` - `HasTransactionSigner` renamed to `AddressWithTransactionSigner` - `HasLsigSigner` renamed to `AddressWithLsigSigner` - `HasProgramDataSigner` renamed to `AddressWithProgramDataSigner` - `HasMxBytesSigner` renamed to `AddressWithMxBytesSigner` - `LogicSigAccount.delegate()` now accepts `LsigSigner` callback instead of full account - `ProgramDataSigner` signature changed to `(data: bytes, program_address: bytes)` ## New Features - Added `sending_address` parameter to `generate_address_with_signers()` for rekeyed account support - Added `logic_multi_signature` (lmsig) field to `LogicSignature` for multisig delegation - Added `sanity_check_program()` validation for TEAL bytecode - Added `decode_logic_signature()` function - Added helper methods to `LogicSigAccount`: - `bytes_to_sign_for_delegation()` - `program_data_to_sign()` - `sign_program_data()` - `addr` property alias - Added `addr` property alias to `MultisigAccount` ## Files Changed - `src/algokit_transact/signer.py` - Protocol renames, `sending_address` param - `src/algokit_transact/signing/logic_signature.py` - Added `lmsig` field - `src/algokit_transact/signing/validation.py` - New file with `sanity_check_program()` - `src/algokit_transact/codec/signed.py` - Added `decode_logic_signature()` - `src/algokit_transact/__init__.py` - Updated exports - `src/algokit_utils/models/account.py` - Major refactor of account classes - `src/algokit_utils/accounts/account_manager.py` - Updated for renames - `src/algokit_utils/protocols/signer.py` - Fixed `ProgramDataSigner` signature - `src/algokit_utils/protocols/account.py` - Updated docstrings ## Related - Aligns with: algorandfoundation/algokit-utils-ts#465 * refactor: replace SigningAccount with AddressWithSigners from algokit-transact - Update imports from algokit_utils to algokit_transact.signer - Replace SigningAccount type hints with AddressWithSigners across 18 test files - Change .address property access to .addr for account objects - Preserve app_address and AccountInformation.address unchanged * chore: moving logic and multi sigs to transact * feat: algo25 implementation (#233) * feat: algo25 implementation * chore: add user facing algo25 export * refactor: migrate algokit_algosdk dependencies to algokit_common - Add get_application_address() to algokit_common/address.py - Add MICROALGOS_TO_ALGOS_RATIO, MIN_TXN_FEE to algokit_common/constants.py - Update account_manager to use algokit_algo25.seed_from_mnemonic() + nacl instead of algosdk.mnemonic.to_private_key() - Replace algosdk.logic.get_application_address() with algokit_common - Replace algosdk.encoding.encode/decode_address() with algokit_common - Replace algosdk.constants.* with algokit_common constants - Update tests to use nacl + algokit_algo25 for account generation This aligns with algokit-utils-ts PR #479 architecture, reducing dependency on vendored algokit_algosdk package. SourceMap and BoxReference remain in algokit_algosdk for now due to complexity. BREAKING CHANGE: Internal imports changed from algokit_algosdk to algokit_common. Public API remains compatible. * refactor: replace SimulationTrace wrapper with algod client type and rename SendingAddress to ReadableAddress - Remove custom SimulationTrace dataclass wrapper from algokit_utils/models/simulate.py - Use SimulateTransactionResult directly from algokit_algod_client.models - Update transaction_composer.py to return raw SimulateTransactionResult from algod responses - Update logic_error.py to use SimulateTransactionResult type - Rename SendingAddress to ReadableAddress in algokit_transact for cross-language consistency with TypeScript BREAKING CHANGE: SimulationTrace class removed; use SimulateTransactionResult instead. Field names differ: `trace` -> `exec_trace`, `logs` -> `txn_result.logs`. SendingAddress renamed to ReadableAddress. * fix(ci): install algokit CLI separately to avoid import conflict The algokit CLI imports from algokit_utils and expects SigningAccount, which was removed in the decoupling branch. Installing algokit as a uv tool gives it its own isolated environment with its bundled algokit_utils. * refactor(ci): remove unused py-algorand-sdk dep and use uvx for algokit - Remove py-algorand-sdk from cicd group (only used in TYPE_CHECKING) - Replace uv tool install + algokit with uvx algokit (simpler, idiomatic) - Empty cicd group kept for potential future CI-only dependencies * chore: refresh uv.lock * refactor: simplify LogicSigAccount, MultisigAccount and program validation --------- Co-authored-by: Daniel McGregor <daniel.mcgregor@makerx.com.au>
1 parent 2e77178 commit 1bb2366

File tree

90 files changed

+4458
-2927
lines changed

Some content is hidden

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

90 files changed

+4458
-2927
lines changed

.github/workflows/build-python.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
enable-cache: true
2525

2626
- name: Install dependencies
27-
run: uv sync --group cicd --group api-generator
27+
run: uv sync --group api-generator
2828

2929
- name: Setup Polytest
3030
uses: algorandfoundation/algokit-polytest/.github/actions/setup-polytest@main
@@ -65,9 +65,9 @@ jobs:
6565
shell: bash
6666
run: |
6767
set -o pipefail
68-
uv run algokit localnet start
68+
uvx algokit localnet start
6969
uv run poe test-ci 2>&1 | tee pytest-coverage.txt
70-
uv run algokit localnet stop
70+
uvx algokit localnet stop
7171
7272
- name: pytest coverage comment - using Python 3.10 on ubuntu-latest
7373
if: matrix.python == '3.10' && matrix.os == 'ubuntu-latest'

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,5 @@ api/specs/
182182
*.xml
183183

184184
.polytest*/
185+
186+
references/

.pre-commit-config.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ repos:
1313
minimum_pre_commit_version: "2.9.2"
1414
pass_filenames: false
1515
files: "^(src|tests)/"
16+
- id: generate-api-clients
17+
name: generate-api-clients
18+
description: "Generate API clients before linting"
19+
entry: uv run poe generate-api-clients
20+
language: system
21+
types_or: [python, pyi]
22+
args: []
23+
require_serial: true
24+
pass_filenames: false
25+
files: "^(src|tests)/"
1626
- id: lint
1727
name: lint
1828
description: "`mypy` and 'ruff' will check Python types for correctness"
@@ -25,10 +35,26 @@ repos:
2535
minimum_pre_commit_version: "2.9.2"
2636
pass_filenames: false
2737
files: "^(src|tests)/"
38+
- id: docs
39+
name: docs
40+
description: "Build documentation (always passes)"
41+
entry: bash -c 'uv run poe docs || true'
42+
language: system
43+
pass_filenames: false
44+
always_run: true
45+
verbose: true
2846
- id: docstrings-check
2947
name: docstrings-check
3048
description: "Check docstrings for correctness"
3149
entry: uv run poe docstrings-check
3250
language: system
3351
types: [python]
3452
files: "^(src)/"
53+
- id: test
54+
name: test
55+
description: "Run pytest as final validation"
56+
entry: uv run pytest
57+
language: system
58+
pass_filenames: false
59+
always_run: true
60+
stages: [pre-commit]

MIGRATION-NOTES.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,74 @@ A collection of notes to consolidate todos during decoupling efforts (similar do
4040

4141
- BoxReference used to be a subclass of algosdk BoxReference, now there is a direct equivalent imported from transact package. Do we want to keep aliasing the BoxReference to transact version or do we want to deprecate and advice consumers to import directly from transact?
4242

43+
## Account and Signer Type Renames (TS Alignment)
44+
45+
### Breaking Changes
46+
47+
| Before | After | Notes |
48+
|--------|-------|-------|
49+
| `SigningAccount` | `AddressWithSigners` | Class renamed; `.address``.addr` |
50+
| `TransactionSignerAccountProtocol` | `AddressWithTransactionSigner` | Protocol renamed; `.address``.addr` |
51+
| `SignerAccountProtocol` | `AddressWithSigners` | Protocol merged into concrete class |
52+
| `LsigSigner` | `DelegatedLsigSigner` | Type alias renamed |
53+
| `AddressWithLsigSigner` | `AddressWithDelegatedLsigSigner` | Protocol renamed |
54+
55+
### Justification
56+
57+
- Aligns with `algokit-utils-ts` naming conventions
58+
- Python uses `AddressWithTransactionSigner` despite having no `Address` type (unlike TS) for cross-SDK consistency
59+
- The `addr` property matches TypeScript's `TransactionSignerAccount.addr`
60+
61+
### Migration
62+
63+
```python
64+
# Before
65+
from algokit_utils import SigningAccount, TransactionSignerAccountProtocol
66+
account = SigningAccount(...)
67+
print(account.address)
68+
69+
# After
70+
from algokit_utils.transact import AddressWithSigners, AddressWithTransactionSigner
71+
account = AddressWithSigners(...)
72+
print(account.addr)
73+
```
74+
75+
## MultisigAccount and LogicSigAccount Relocation (TS Alignment)
76+
77+
### Breaking Changes
78+
79+
| Before | After | Notes |
80+
|--------|-------|-------|
81+
| `algokit_utils.models.account.MultisigAccount` | `algokit_transact.MultisigAccount` | Moved to transact package |
82+
| `algokit_utils.models.account.MultisigMetadata` | `algokit_transact.MultisigMetadata` | Moved to transact package; `.addresses``.addrs` |
83+
| `algokit_utils.models.account.LogicSigAccount` | `algokit_transact.LogicSigAccount` | Moved to transact package |
84+
85+
### Justification
86+
87+
- Aligns with `algokit-utils-ts` PR #465 which moved these classes to `@algorandfoundation/algokit-transact`
88+
- `MultisigMetadata.addrs` matches TypeScript's `MultisigMetadata.addrs` property
89+
90+
### Backward Compatibility
91+
92+
Classes remain importable from original locations via re-exports:
93+
- `algokit_utils.models.account` (re-exports from transact)
94+
- `algokit_utils.transact` (re-exports from transact)
95+
96+
### Migration
97+
98+
```python
99+
# Before
100+
from algokit_utils.models.account import MultisigAccount, MultisigMetadata, LogicSigAccount
101+
metadata = MultisigMetadata(version=1, threshold=2, addresses=["addr1", "addr2"])
102+
103+
# After (preferred)
104+
from algokit_transact import MultisigAccount, MultisigMetadata, LogicSigAccount
105+
metadata = MultisigMetadata(version=1, threshold=2, addrs=["addr1", "addr2"])
106+
107+
# Or via algokit_utils.transact
108+
from algokit_utils.transact import MultisigAccount, MultisigMetadata, LogicSigAccount
109+
```
110+
43111
## Contributing Guide
44112

45113
- Introduce comprehensive contributing guide around running tests/updating snapshots in API client tests and dealing with Polytest

0 commit comments

Comments
 (0)