algokit-utils 3.0.0b10__py3-none-any.whl → 3.0.0b12__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.

Potentially problematic release.


This version of algokit-utils might be problematic. Click here for more details.

@@ -19,63 +19,58 @@ __all__ = ["AccountAssetInformation", "AssetInformation", "AssetManager", "BulkA
19
19
 
20
20
  @dataclass(kw_only=True, frozen=True)
21
21
  class AccountAssetInformation:
22
- """Information about an account's holding of a particular asset.
23
-
24
- :ivar asset_id: The ID of the asset
25
- :ivar balance: The amount of the asset held by the account
26
- :ivar frozen: Whether the asset is frozen for this account
27
- :ivar round: The round this information was retrieved at
28
- """
22
+ """Information about an account's holding of a particular asset."""
29
23
 
30
24
  asset_id: int
25
+ """The ID of the asset"""
31
26
  balance: int
27
+ """The amount of the asset held by the account"""
32
28
  frozen: bool
29
+ """Whether the asset is frozen for this account"""
33
30
  round: int
31
+ """The round this information was retrieved at"""
34
32
 
35
33
 
36
34
  @dataclass(kw_only=True, frozen=True)
37
35
  class AssetInformation:
38
- """Information about an Algorand Standard Asset (ASA).
39
-
40
- :ivar asset_id: The ID of the asset
41
- :ivar creator: The address of the account that created the asset
42
- :ivar total: The total amount of the smallest divisible units that were created of the asset
43
- :ivar decimals: The amount of decimal places the asset was created with
44
- :ivar default_frozen: Whether the asset was frozen by default for all accounts, defaults to None
45
- :ivar manager: The address of the optional account that can manage the configuration of the asset and destroy it,
46
- defaults to None
47
- :ivar reserve: The address of the optional account that holds the reserve (uncirculated supply) units of the asset,
48
- defaults to None
49
- :ivar freeze: The address of the optional account that can be used to freeze or unfreeze holdings of this asset,
50
- defaults to None
51
- :ivar clawback: The address of the optional account that can clawback holdings of this asset from any account,
52
- defaults to None
53
- :ivar unit_name: The optional name of the unit of this asset (e.g. ticker name), defaults to None
54
- :ivar unit_name_b64: The optional name of the unit of this asset as bytes, defaults to None
55
- :ivar asset_name: The optional name of the asset, defaults to None
56
- :ivar asset_name_b64: The optional name of the asset as bytes, defaults to None
57
- :ivar url: Optional URL where more information about the asset can be retrieved, defaults to None
58
- :ivar url_b64: Optional URL where more information about the asset can be retrieved as bytes, defaults to None
59
- :ivar metadata_hash: 32-byte hash of some metadata that is relevant to the asset and/or asset holders,
60
- defaults to None
61
- """
36
+ """Information about an Algorand Standard Asset (ASA)."""
62
37
 
63
38
  asset_id: int
39
+ """The ID of the asset"""
64
40
  creator: str
41
+ """The address of the account that created the asset"""
65
42
  total: int
43
+ """The total amount of the smallest divisible units that were created of the asset"""
66
44
  decimals: int
45
+ """The amount of decimal places the asset was created with"""
67
46
  default_frozen: bool | None = None
47
+ """Whether the asset was frozen by default for all accounts, defaults to None"""
68
48
  manager: str | None = None
49
+ """The address of the optional account that can manage the configuration of the asset and destroy it,
50
+ defaults to None"""
69
51
  reserve: str | None = None
52
+ """The address of the optional account that holds the reserve (uncirculated supply) units of the asset,
53
+ defaults to None"""
70
54
  freeze: str | None = None
55
+ """The address of the optional account that can be used to freeze or unfreeze holdings of this asset,
56
+ defaults to None"""
71
57
  clawback: str | None = None
58
+ """The address of the optional account that can clawback holdings of this asset from any account,
59
+ defaults to None"""
72
60
  unit_name: str | None = None
61
+ """The optional name of the unit of this asset (e.g. ticker name), defaults to None"""
73
62
  unit_name_b64: bytes | None = None
63
+ """The optional name of the unit of this asset as bytes, defaults to None"""
74
64
  asset_name: str | None = None
65
+ """The optional name of the asset, defaults to None"""
75
66
  asset_name_b64: bytes | None = None
67
+ """The optional name of the asset as bytes, defaults to None"""
76
68
  url: str | None = None
69
+ """The optional URL where more information about the asset can be retrieved, defaults to None"""
77
70
  url_b64: bytes | None = None
71
+ """The optional URL where more information about the asset can be retrieved as bytes, defaults to None"""
78
72
  metadata_hash: bytes | None = None
73
+ """The 32-byte hash of some metadata that is relevant to the asset and/or asset holders, defaults to None"""
79
74
 
80
75
 
81
76
  @dataclass(kw_only=True, frozen=True)
@@ -87,7 +82,9 @@ class BulkAssetOptInOutResult:
87
82
  """
88
83
 
89
84
  asset_id: int
85
+ """The ID of the asset opted into / out of"""
90
86
  transaction_id: str
87
+ """The transaction ID of the resulting opt in / out"""
91
88
 
92
89
 
93
90
  class AssetManager:
@@ -95,6 +92,9 @@ class AssetManager:
95
92
 
96
93
  :param algod_client: An algod client
97
94
  :param new_group: A function that creates a new TransactionComposer transaction group
95
+
96
+ :example:
97
+ >>> asset_manager = AssetManager(algod_client)
98
98
  """
99
99
 
100
100
  def __init__(self, algod_client: algod.AlgodClient, new_group: Callable[[], TransactionComposer]):
@@ -106,6 +106,10 @@ class AssetManager:
106
106
 
107
107
  :param asset_id: The ID of the asset
108
108
  :return: The asset information
109
+
110
+ :example:
111
+ >>> asset_manager = AssetManager(algod_client)
112
+ >>> asset_info = asset_manager.get_by_id(1234567890)
109
113
  """
110
114
  asset = self._algod.asset_info(asset_id)
111
115
  assert isinstance(asset, dict)
@@ -138,6 +142,10 @@ class AssetManager:
138
142
  :param sender: The address of the sender/account to look up
139
143
  :param asset_id: The ID of the asset to return a holding for
140
144
  :return: The account asset holding information
145
+
146
+ :example:
147
+ >>> asset_manager = AssetManager(algod_client)
148
+ >>> account_asset_info = asset_manager.get_account_information(sender, asset_id)
141
149
  """
142
150
  address = self._get_address_from_sender(sender)
143
151
  info = self._algod.account_asset_info(address, asset_id)
@@ -182,6 +190,10 @@ class AssetManager:
182
190
  :param last_valid_round: The last valid round to include in the transaction, defaults to None
183
191
  :param send_params: The send parameters to use for the transaction, defaults to None
184
192
  :return: An array of records matching asset ID to transaction ID of the opt in
193
+
194
+ :example:
195
+ >>> asset_manager = AssetManager(algod_client)
196
+ >>> results = asset_manager.bulk_opt_in(account, asset_ids)
185
197
  """
186
198
  results: list[BulkAssetOptInOutResult] = []
187
199
  sender = self._get_address_from_sender(account)
@@ -249,6 +261,10 @@ class AssetManager:
249
261
  :param send_params: The send parameters to use for the transaction, defaults to None
250
262
  :raises ValueError: If ensure_zero_balance is True and account has non-zero balance or is not opted in
251
263
  :return: An array of records matching asset ID to transaction ID of the opt out
264
+
265
+ :example:
266
+ >>> asset_manager = AssetManager(algod_client)
267
+ >>> results = asset_manager.bulk_opt_out(account, asset_ids)
252
268
  """
253
269
  results: list[BulkAssetOptInOutResult] = []
254
270
  sender = self._get_address_from_sender(account)
@@ -64,10 +64,15 @@ class NetworkDetail:
64
64
  """
65
65
 
66
66
  is_testnet: bool
67
+ """Whether the network is a testnet"""
67
68
  is_mainnet: bool
69
+ """Whether the network is a mainnet"""
68
70
  is_localnet: bool
71
+ """Whether the network is a localnet"""
69
72
  genesis_id: str
73
+ """The genesis ID of the network"""
70
74
  genesis_hash: str
75
+ """The genesis hash of the network"""
71
76
 
72
77
 
73
78
  def _get_config_from_environment(environment_prefix: str) -> AlgoClientNetworkConfig:
@@ -88,6 +93,17 @@ class ClientManager:
88
93
 
89
94
  :param clients_or_configs: Either client instances or client configurations
90
95
  :param algorand_client: AlgorandClient instance
96
+
97
+ :example:
98
+ >>> # Algod only
99
+ >>> client_manager = ClientManager(algod_client)
100
+ >>> # Algod and Indexer
101
+ >>> client_manager = ClientManager(algod_client, indexer_client)
102
+ >>> # Algod config only
103
+ >>> client_manager = ClientManager(ClientManager.get_algod_config_from_environment())
104
+ >>> # Algod and Indexer config
105
+ >>> client_manager = ClientManager(ClientManager.get_algod_config_from_environment(),
106
+ ... ClientManager.get_indexer_config_from_environment())
91
107
  """
92
108
 
93
109
  def __init__(self, clients_or_configs: AlgoClientConfigs | AlgoSdkClients, algorand_client: AlgorandClient):
@@ -151,6 +167,10 @@ class ClientManager:
151
167
  """Get details about the connected Algorand network.
152
168
 
153
169
  :return: Network details including type and genesis information
170
+
171
+ :example:
172
+ >>> client_manager = ClientManager(algod_client)
173
+ >>> network_detail = client_manager.network()
154
174
  """
155
175
  if self._suggested_params is None:
156
176
  self._suggested_params = self._algod.suggested_params()
@@ -417,6 +437,9 @@ class ClientManager:
417
437
 
418
438
  :param genesis_id: Genesis ID to check
419
439
  :return: True if genesis ID indicates a local network
440
+
441
+ :example:
442
+ >>> ClientManager.genesis_id_is_localnet("devnet-v1")
420
443
  """
421
444
  return genesis_id in ["devnet-v1", "sandnet-v1", "dockernet-v1"]
422
445
 
@@ -442,6 +465,14 @@ class ClientManager:
442
465
  :param app_lookup_cache: Optional app lookup cache
443
466
  :raises ValueError: If no Algorand client is configured
444
467
  :return: Typed application client instance
468
+
469
+ :example:
470
+ >>> client_manager = ClientManager(algod_client)
471
+ >>> typed_app_client = client_manager.get_typed_app_client_by_creator_and_name(
472
+ ... typed_client=MyAppClient,
473
+ ... creator_address="creator_address",
474
+ ... app_name="app_name",
475
+ ... )
445
476
  """
446
477
  if not self._algorand:
447
478
  raise ValueError("Attempt to get app client from a ClientManager without an Algorand client")
@@ -478,6 +509,13 @@ class ClientManager:
478
509
  :param clear_source_map: Optional clear program source map
479
510
  :raises ValueError: If no Algorand client is configured
480
511
  :return: Typed application client instance
512
+
513
+ :example:
514
+ >>> client_manager = ClientManager(algod_client)
515
+ >>> typed_app_client = client_manager.get_typed_app_client_by_id(
516
+ ... typed_client=MyAppClient,
517
+ ... app_id=1234567890,
518
+ ... )
481
519
  """
482
520
  if not self._algorand:
483
521
  raise ValueError("Attempt to get app client from a ClientManager without an Algorand client")
@@ -515,6 +553,13 @@ class ClientManager:
515
553
  :param clear_source_map: Optional clear program source map
516
554
  :raises ValueError: If no Algorand client is configured
517
555
  :return: The typed client instance
556
+
557
+ :example:
558
+ >>> client_manager = ClientManager(algod_client)
559
+ >>> typed_app_client = client_manager.get_typed_app_client_by_network(
560
+ ... typed_client=MyAppClient,
561
+ ... app_name="app_name",
562
+ ... )
518
563
  """
519
564
  if not self._algorand:
520
565
  raise ValueError("Attempt to get app client from a ClientManager without an Algorand client")
@@ -548,6 +593,13 @@ class ClientManager:
548
593
  :param compilation_params: Optional compilation parameters
549
594
  :raises ValueError: If no Algorand client is configured
550
595
  :return: Typed application factory instance
596
+
597
+ :example:
598
+ >>> client_manager = ClientManager(algod_client)
599
+ >>> typed_app_factory = client_manager.get_typed_app_factory(
600
+ ... typed_factory=MyAppFactory,
601
+ ... app_name="app_name",
602
+ ... )
551
603
  """
552
604
  if not self._algorand:
553
605
  raise ValueError("Attempt to get app factory from a ClientManager without an Algorand client")
@@ -569,6 +621,10 @@ class ClientManager:
569
621
  otherwise it will use default localnet configuration.
570
622
 
571
623
  :return: Configuration for algod, indexer, and optionally kmd
624
+
625
+ :example:
626
+ >>> client_manager = ClientManager(algod_client)
627
+ >>> config = client_manager.get_config_from_environment_or_localnet()
572
628
  """
573
629
  algod_server = os.getenv("ALGOD_SERVER")
574
630
 
@@ -609,6 +665,10 @@ class ClientManager:
609
665
 
610
666
  :param config_or_port: Service name or port number
611
667
  :return: Client configuration for local network
668
+
669
+ :example:
670
+ >>> client_manager = ClientManager(algod_client)
671
+ >>> config = client_manager.get_default_localnet_config("algod")
612
672
  """
613
673
  port = (
614
674
  config_or_port
@@ -624,6 +684,10 @@ class ClientManager:
624
684
  Will raise an error if ALGOD_SERVER environment variable is not set
625
685
 
626
686
  :return: Algod client configuration
687
+
688
+ :example:
689
+ >>> client_manager = ClientManager(algod_client)
690
+ >>> config = client_manager.get_algod_config_from_environment()
627
691
  """
628
692
  return _get_config_from_environment("ALGOD")
629
693
 
@@ -633,6 +697,10 @@ class ClientManager:
633
697
  Will raise an error if INDEXER_SERVER environment variable is not set
634
698
 
635
699
  :return: Indexer client configuration
700
+
701
+ :example:
702
+ >>> client_manager = ClientManager(algod_client)
703
+ >>> config = client_manager.get_indexer_config_from_environment()
636
704
  """
637
705
  return _get_config_from_environment("INDEXER")
638
706
 
@@ -641,6 +709,10 @@ class ClientManager:
641
709
  """Retrieve the kmd configuration from environment variables.
642
710
 
643
711
  :return: KMD client configuration
712
+
713
+ :example:
714
+ >>> client_manager = ClientManager(algod_client)
715
+ >>> config = client_manager.get_kmd_config_from_environment()
644
716
  """
645
717
  return _get_config_from_environment("KMD")
646
718
 
@@ -653,6 +725,10 @@ class ClientManager:
653
725
  :param network: Which network to connect to - TestNet or MainNet
654
726
  :param config: Which algod config to return - Algod or Indexer
655
727
  :return: Configuration for the specified network and service
728
+
729
+ :example:
730
+ >>> client_manager = ClientManager(algod_client)
731
+ >>> config = client_manager.get_algonode_config("testnet", "algod")
656
732
  """
657
733
  service_type = "api" if config == "algod" else "idx"
658
734
  return AlgoClientNetworkConfig(
@@ -2,8 +2,10 @@ import contextlib
2
2
  import enum
3
3
  import os
4
4
  from dataclasses import dataclass
5
+ from typing import overload
5
6
 
6
7
  import httpx
8
+ from typing_extensions import deprecated
7
9
 
8
10
  from algokit_utils.config import config
9
11
 
@@ -34,19 +36,25 @@ class DispenserAssetName(enum.IntEnum):
34
36
  @dataclass
35
37
  class DispenserAsset:
36
38
  asset_id: int
39
+ """The ID of the asset"""
37
40
  decimals: int
41
+ """The amount of decimal places the asset was created with"""
38
42
  description: str
43
+ """The description of the asset"""
39
44
 
40
45
 
41
46
  @dataclass
42
47
  class DispenserFundResponse:
43
48
  tx_id: str
49
+ """The transaction ID of the funded transaction"""
44
50
  amount: int
51
+ """The amount of Algos funded"""
45
52
 
46
53
 
47
54
  @dataclass
48
55
  class DispenserLimitResponse:
49
56
  amount: int
57
+ """The amount of Algos that can be funded"""
50
58
 
51
59
 
52
60
  DISPENSER_ASSETS = {
@@ -136,16 +144,37 @@ class TestNetDispenserApiClient:
136
144
  logger.debug(f"{error_message}: {err}", exc_info=True)
137
145
  raise err
138
146
 
139
- def fund(self, address: str, amount: int, asset_id: int) -> DispenserFundResponse:
147
+ @overload
148
+ def fund(self, address: str, amount: int) -> DispenserFundResponse: ...
149
+
150
+ @deprecated("Asset ID parameter is deprecated. Can now use `fund(address, amount)` instead.")
151
+ @overload
152
+ def fund(self, address: str, amount: int, asset_id: int | None = None) -> DispenserFundResponse: ...
153
+
154
+ def fund(self, address: str, amount: int, asset_id: int | None = None) -> DispenserFundResponse: # noqa: ARG002
140
155
  """
141
156
  Fund an account with Algos from the dispenser API
157
+
158
+ :param address: The address to fund
159
+ :param amount: The amount of Algos to fund
160
+ :param asset_id: The asset ID to fund (deprecated)
161
+ :return: The transaction ID of the funded transaction
162
+ :raises Exception: If the dispenser API request fails
163
+
164
+ :example:
165
+ >>> dispenser_client = TestNetDispenserApiClient()
166
+ >>> dispenser_client.fund(address="SENDER_ADDRESS", amount=1000000)
142
167
  """
143
168
 
144
169
  try:
145
170
  response = self._process_dispenser_request(
146
171
  auth_token=self.auth_token,
147
- url_suffix=f"fund/{asset_id}",
148
- data={"receiver": address, "amount": amount, "assetID": asset_id},
172
+ url_suffix=f"fund/{DISPENSER_ASSETS[DispenserAssetName.ALGO].asset_id}",
173
+ data={
174
+ "receiver": address,
175
+ "amount": amount,
176
+ "assetID": DISPENSER_ASSETS[DispenserAssetName.ALGO].asset_id,
177
+ },
149
178
  method="POST",
150
179
  )
151
180
 
@@ -19,43 +19,73 @@ __all__ = [
19
19
  @dataclass(kw_only=True, frozen=True)
20
20
  class AppState:
21
21
  key_raw: bytes
22
+ """The key of the state as raw bytes"""
22
23
  key_base64: str
24
+ """The key of the state"""
23
25
  value_raw: bytes | None
26
+ """The value of the state as raw bytes"""
24
27
  value_base64: str | None
28
+ """The value of the state as base64 encoded string"""
25
29
  value: str | int
30
+ """The value of the state as a string or integer"""
26
31
 
27
32
 
28
33
  @dataclass(kw_only=True, frozen=True)
29
34
  class AppInformation:
30
35
  app_id: int
36
+ """The ID of the application"""
31
37
  app_address: str
38
+ """The address of the application"""
32
39
  approval_program: bytes
40
+ """The approval program"""
33
41
  clear_state_program: bytes
42
+ """The clear state program"""
34
43
  creator: str
44
+ """The creator of the application"""
35
45
  global_state: dict[str, AppState]
46
+ """The global state of the application"""
36
47
  local_ints: int
48
+ """The number of local ints"""
37
49
  local_byte_slices: int
50
+ """The number of local byte slices"""
38
51
  global_ints: int
52
+ """The number of global ints"""
39
53
  global_byte_slices: int
54
+ """The number of global byte slices"""
40
55
  extra_program_pages: int | None
56
+ """The number of extra program pages"""
41
57
 
42
58
 
43
59
  @dataclass(kw_only=True, frozen=True)
44
60
  class CompiledTeal:
61
+ """The compiled teal code"""
62
+
45
63
  teal: str
64
+ """The teal code"""
46
65
  compiled: str
66
+ """The compiled teal code"""
47
67
  compiled_hash: str
68
+ """The compiled hash"""
48
69
  compiled_base64_to_bytes: bytes
70
+ """The compiled base64 to bytes"""
49
71
  source_map: algosdk.source_map.SourceMap | None
50
72
 
51
73
 
52
74
  @dataclass(kw_only=True, frozen=True)
53
75
  class AppCompilationResult:
76
+ """The compiled teal code"""
77
+
54
78
  compiled_approval: CompiledTeal
79
+ """The compiled approval program"""
55
80
  compiled_clear: CompiledTeal
81
+ """The compiled clear state program"""
56
82
 
57
83
 
58
84
  @dataclass(kw_only=True, frozen=True)
59
85
  class AppSourceMaps:
86
+ """The source maps for the application"""
87
+
60
88
  approval_source_map: SourceMap | None = None
89
+ """The source map for the approval program"""
61
90
  clear_source_map: SourceMap | None = None
91
+ """The source map for the clear state program"""
@@ -19,15 +19,24 @@ __all__ = [
19
19
 
20
20
  @dataclass(kw_only=True, frozen=True)
21
21
  class BoxName:
22
+ """The name of the box"""
23
+
22
24
  name: str
25
+ """The name of the box as a string"""
23
26
  name_raw: bytes
27
+ """The name of the box as raw bytes"""
24
28
  name_base64: str
29
+ """The name of the box as a base64 encoded string"""
25
30
 
26
31
 
27
32
  @dataclass(kw_only=True, frozen=True)
28
33
  class BoxValue:
34
+ """The value of the box"""
35
+
29
36
  name: BoxName
37
+ """The name of the box"""
30
38
  value: bytes
39
+ """The value of the box as raw bytes"""
31
40
 
32
41
 
33
42
  class DataTypeFlag(IntEnum):