Python Utils v3 Migration Guide | Algorand Developer Portal
Python Utils v3 Migration Guide
Version 3 of algokit-utils-ts moved from a stateless function-based interface to a stateful class-based interfaces. This change allows for:
- Easier and simpler consumption experience guided by IDE autocompletion
- Less redundant parameter passing (e.g.,
algodclient) - Better performance through caching of commonly retrieved values like transaction parameters
- More consistent and intuitive API design
- Stronger type safety and better error messages
- Improved ARC-56 compatibility
- Feature parity with
algokit-utils-ts>=v7interfaces
The entry point to most functionality in AlgoKit Utils is now available via a single entry-point, the AlgorandClient class.
The v2 interfaces and abstractions will be removed in future major version bumps, however in order to ensure gradual migration, all v2 abstractions are available with respective deprecation warnings. The new way to use AlgoKit Utils is via the AlgorandClient class, which is easier, simpler, and more convenient to use and has powerful new features.
BREAKING CHANGE: the
betamodule is now removed, any imports fromalgokit_utils.betawill now raise an error with a link to a new expected import path. This is due to the fact that the interfaces introduced inbetaare now refined and available in the main module.
Migration Steps
In general, your codebase might fall into one of the following migration scenarios:
- Using
algokit-utils-pyv2.x only without use of abstractions frombetamodule - Using
algokit-utils-pyv2.x only and with use of abstractions frombetamodule - Using
algokit-utils-pyv2.x withalgokit-client-generator-pyv1.x - Using
algokit-client-generator-pyv1.x only (implies implicit dependency onalgokit-utils-pyv2.x)
Given that algokit-utils-py v3.x is backwards compatible with algokit-client-generator-py v1.x, the following general guidelines are applicable to all scenarios (note that the order of operations is important to ensure straight-forward migration):
- Upgrade to
algokit-utils-pyv3.x- 1.1 (If used) Update imports from
algokit_utils.betatoalgokit_utils - 1.2 Follow hints in deprecation warnings to update your codebase to rely on latest v3 interfaces
- 1.1 (If used) Update imports from
- Upgrade to
algokit-client-generator-pyv2.x and regenerate typed clients- 2.1 Follow
algokit-client-generator-pyv2.x migration guide
- 2.1 Follow
Prerequisites
It is important to reiterate that if you have previously relied on beta versions of algokit-utils-py v2.x, you will need to update your imports to rely on the new interfaces. Errors thrown during import from beta will provide a description of the new expected import path.
As with
v2.xall public abstractions inalgokit_utilsare available for direct importsfrom algokit_utils import ..., however underlying modules have been refined to be structured loosely around common AVM domains such asapplications,transactions,accounts,assets, etc. See API reference for latest and detailed overview.
Step 1 - Replace SDK Clients with AlgorandClient
First, replace your SDK client initialization with AlgorandClient. Look for get_algod_client calls and replace with an appropriate AlgorandClient initialization:
"""Before"""
import algokit_utils
algod = algokit_utils.get_algod_client()
indexer = algokit_utils.get_indexer_client()
"""After"""
from algokit_utils import AlgorandClient
algorand = AlgorandClient.from_environment() # or .testnet(), .mainnet(), etc.
During migration, you can still access SDK clients if needed:
algod = algorand.client.algod
indexer = algorand.client.indexer
kmd = algorand.client.kmd
Step 2 - Update Account Management
Account management has moved to algorand.account:
Before:
account = algokit_utils.get_account_from_mnemonic(
mnemonic=os.getenv("MY_ACCOUNT_MNEMONIC"),
)
dispenser = algokit_utils.get_dispenser_account(algod)
After:
account = algorand.account.from_mnemonic(os.getenv("MY_ACCOUNT_MNEMONIC"))
dispenser = algorand.account.dispenser_from_environment()
Key changes:
get_account→account.from_environmentget_account_from_mnemonic→account.from_mnemonicget_dispenser_account→account.dispenser_from_environmentget_localnet_default_account→account.localnet_dispenser
Step 3 - Update Transaction Management
Transaction creation and sending is now more structured:
Before:
result = algokit_utils.transfer_algos(
from_account=account,
to_addr="RECEIVER",
amount=algokit_utils.algos(1),
algod_client=algod,
)
# Transaction groups
atc = AtomicTransactionComposer()
# ... add transactions ...
result = algokit_utils.execute_atc_with_logic_error(atc, algod)
After:
# Single transaction
result = algorand.send.payment(
sender=account.address,
receiver="RECEIVER",
amount=AlgoAmount.from_algo(1),
)
# Transaction groups
composer = algorand.new_group()
# ... add transactions ...
result = composer.send()
Key changes:
transfer_algos→algorand.send.paymenttransfer_asset→algorand.send.asset_transferexecute_atc_with_logic_error→composer.send()- Transaction parameters are now more consistently named (e.g.,
senderinstead offrom_account) - Improved amount handling with dedicated
AlgoAmountclass (e.g.,AlgoAmount.from_algo(1))
Step 4 - Update ApplicationSpecification usage
ApplicationSpecification abstraction is largely identical to v2, however it’s been renamed to Arc32Contract to better reflect the fact that it’s a contract specification for a specific ARC and addition of Arc56Contract supporting the latest recommended conventions. Hence the main actionable change is to update your import to from algokit_utils import Arc32Contract and rename ApplicationSpecification to Arc32Contract.
You can instantiate an Arc56Contract instance from an Arc32Contract instance using the Arc56Contract.from_arc32 method. For instance:
testing_app_arc32_app_spec = Arc32Contract.from_json(app_spec_json)
arc56_app_spec = Arc56Contract.from_arc32(testing_app_arc32_app_spec)
Despite auto conversion of ARC-32 to ARC-56, we recommend recompiling your contract to a fully compliant ARC-56 specification given that auto conversion would skip populating information that can’t be parsed from raw ARC-32.
Step 5 - Replace ApplicationClient usage
The existing ApplicationClient (untyped app client) class is still present until at least v4, but it’s worthwhile migrating to the new AppClient and AppFactory classes. These new clients are ARC-56 compatible, but also support ARC-32 app specs and will continue to support this indefinitely until such time the community deems they are deprecated.
All of the functionality in ApplicationClient is available within the new classes, but their interface is slightly different to make it easier to use and more consistent with the new AlgorandClient functionality. The key existing methods that have changed all have @deprecation notices to help guide you on this, but broadly the changes are:
The app resolution semantics, now have static methods that determine different ways of constructing a client and the constructor itself is very simple (requiring
app_id)If you want to call
createordeploythen you need anAppFactoryto do that, and then it will in turn give you anAppClientinstance that is connected to the app you just created / deployed. This significantly simplifies the app client because now the app client has a clear operating purpose: allow for calls and state management for an instance of an app, whereas the app factory handles all of the calls when you don’t have an instance yet (or may or may not have an instance in the case ofdeploy).This means that you can simply access
client.app_idandclient.app_addressonAppClientsince these values are known statically and won’t change (previously associated calls toapp_address,app_idproperties potentially required extra API calls as the values weren’t always available).Adding
fund_app_accountwhich serves as a convenience method to top up the balance of address associated with application.All of the methods that return or execute a transaction (
update,call,opt_in, etc.) are now exposed in an interface similar to the one inAlgorandClient, namely (where{call_type}is one of:update/delete/opt_in/close_out/clear_state/call):appClient.create_transaction.{callType}to get a transaction for an ABI method callappClient.send.{call_type}to sign and send a transaction for an ABI method callappClient.params.{call_type}to get a params object for an ABI method callappClient.create_transaction.bare.{call_type}to get a transaction for a bare app callappClient.send.bare.{call_type}to sign and send a transaction for a bare app callappClient.params.bare.{call_type}to get a params object for a bare app call
The semantics to resolve the application is now available via simpler entrypoints within
algorand.clientWhen making an ABI method call, the method arguments property is are now passed via explicit
argsfield in a parameters dataclass applicable to the method call.The foreign reference arrays have been renamed to align with typed parameters on
tsand related corealgosdk:boxes->box_referencesapps->app_referencesassets->asset_referencesaccounts->account_references
The return value for methods that send a transaction will have any ABI return value directly in the
abi_returnproperty rather than the low level algosdkABIResulttype while also automatically decoding values based on provided ARC56 spec.
Step 6 - Replace typed app client usage
Version 2 of the Python typed app client generator introduces breaking changes to the generated client that support the new AppFactory and AppClient functionality along with adding ARC-56 support. The generated client has better typing support for things like state commensurate with the new capabilities within ARC-56.
It’s worth noting that because we have maintained backwards compatibility with the pre v2 algokit-utils-py stateless functions, older typed clients generated using version 1 of the Python typed client generator will work against v3 of utils, however you won’t have access to the new features or ARC-56 support.
If you want to convert from an older typed client to a new one you will need to make certain changes. Refer to client generator v2 migration guide.
Step 7 - Update AppClient State Management
State management is now more structured and type-safe:
"""Before"""
global_state = app_client.get_global_state()
local_state = app_client.get_local_state(account_address)
box_value = app_client.get_box_value("box_name")
"""After"""
# Global state
global_state = app_client.state.global_state.get_all()
value = app_client.state.global_state.get_value("key_name")
map_value = app_client.state.global_state.get_map_value("map_name", "key")
# Local state
local_state = app_client.state.local_state(account_address).get_all()
value = app_client.state.local_state(account_address).get_value("key_name")
map_value = app_client.state.local_state(account_address).get_map_value("map_name", "key")
# Box storage
box_value = app_client.state.box.get_value("box_name")
boxes = app_client.state.box.get_all()
map_value = app_client.state.box.get_map_value("map_name", "key")
Step 8 - Update Asset Management
Asset management is now more consistent:
"""Before"""
result = algokit_utils.opt_in(algod, account, [asset_id])
"""After"""
result = algorand.send.asset_opt_in(
params=AssetOptInParams(
sender=account.address,
asset_id=asset_id,
)
)
Breaking Changes
- Client Management
- Removal of standalone client creation functions
- All clients now accessed through
AlgorandClient
- Account Management
- Account creation functions moved to
AccountManageraccessible viaalgorand.accountproperty - Unified
TransactionSignerAccountProtocolwith compliant and typedSigningAccount,TransactionSignerAccount,LogicSigAccount,MultiSigAccountclasses encapsulating low levelalgosdkabstractions. - Improved typing for account operations, such as obtaining account information from
algod, returning a typed information object.
- Account creation functions moved to
- Transaction Management
- Consistent and intuitive transaction creation and sending interface accessible via
algorand.{send|params|create_transaction}properties - New transaction composition interface accessible via
algorand.new_group - Removing necessity to interact with low level and untyped
algosdkabstractions for assembling, signing and sending transaction(s).
- Consistent and intuitive transaction creation and sending interface accessible via
- Application Client
- Split into
AppClient,AppDeployerandAppFactory deploymethod inAppFactory/AppDeployerno longer auto increments the contract version by default. It is the user’s responsibility to explicitly manage versioning of their smart contracts (if desired).- New intuitive structured interface for creating or sending
AppCall|AppMethodCalltransactions - ARC-56 support along with automatic conversion of specs from ARC-32 to ARC-56
- Split into
- State Management
- New hierarchical state access available via
app_client.state.{global_state|local_state|box}properties - Improved typing for state values
- Support for ARC-56 state schemas
- New hierarchical state access available via
- Asset Management
- Dedicated
AssetManagerclass for asset management accessible viaalgorand.assetproperty - Improved typing for asset operations, such as obtaining asset information from
algod, returning a typed information object. - Consistent interface for asset opt-in, transfer, freeze, etc.
- Dedicated
Best Practices
- Use the new
AlgorandClientas the main entry point - Leverage IDE autocompletion to discover available functionality, consult with API reference when unsure
- Use the transaction parameter builders for type-safe transaction creation (
algorand.params.{}) - Use the state accessor patterns for cleaner state management {
algorand.state.{}} - Use high level
TransactionComposerinterface over low levelalgosdkabstractions (where possible) - Use source maps and debug mode to quickly troubleshoot on-chain errors
- Use idempotent deployment patterns with versioning
Troubleshooting
A v2 interface/method/class does not display a deprecation warning correctly or at all
Submit an issue to algokit-utils-py with a description of the problem and the code that is causing it.
Useful scenario of converting v2 to v3 not covered in generic migration guide
If you have a scenario that you think is useful and not covered in the generic migration guide, please submit an issue to algokit-utils-py with a scenario.