From cb218737b99d3fd6e4906f9f6165f97bff271bb3 Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Wed, 16 Mar 2022 12:42:32 -0400 Subject: [PATCH 1/3] Fix the cucumber test wording around block rounds in indexer asset balance lookup (#301) --- test/steps/v2_steps.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/steps/v2_steps.py b/test/steps/v2_steps.py index f332743e..569e50d1 100644 --- a/test/steps/v2_steps.py +++ b/test/steps/v2_steps.py @@ -369,14 +369,13 @@ def check_asset_balance(context, numaccounts, account, isfrozen, amount): @when( - 'we make a Lookup Asset Balances call against asset index {index} with limit {limit} afterAddress "{afterAddress:MaybeString}" round {block} currencyGreaterThan {currencyGreaterThan} currencyLessThan {currencyLessThan}' + 'we make a Lookup Asset Balances call against asset index {index} with limit {limit} afterAddress "{afterAddress:MaybeString}" currencyGreaterThan {currencyGreaterThan} currencyLessThan {currencyLessThan}' ) def asset_balance( context, index, limit, afterAddress, - block, currencyGreaterThan, currencyLessThan, ): @@ -386,7 +385,6 @@ def asset_balance( next_page=None, min_balance=int(currencyGreaterThan), max_balance=int(currencyLessThan), - block=int(block), ) From 3025489e31b9c86cfa11fccd50cd44134da68e34 Mon Sep 17 00:00:00 2001 From: nicholasguoalgorand <67928479+nicholasguoalgorand@users.noreply.github.com> Date: Thu, 17 Mar 2022 11:34:59 -0700 Subject: [PATCH 2/3] Support unlimited assets REST API changes. (#295) --- Makefile | 2 +- algosdk/v2client/algod.py | 31 +++++- algosdk/v2client/indexer.py | 189 +++++++++++++++++++++++++++++++++++- test/steps/v2_steps.py | 101 +++++++++++++++++++ 4 files changed, 316 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 7c39b1e7..0a985ce4 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -UNITS = "@unit.abijson or @unit.algod or @unit.applications or @unit.atomic_transaction_composer or @unit.dryrun or @unit.feetest or @unit.indexer or @unit.indexer.logs or @unit.offline or @unit.rekey or @unit.transactions.keyreg or @unit.responses or @unit.responses.231 or @unit.tealsign or @unit.transactions or @unit.transactions.payment" +UNITS = "@unit.abijson or @unit.algod or @unit.applications or @unit.atomic_transaction_composer or @unit.dryrun or @unit.feetest or @unit.indexer or @unit.indexer.logs or @unit.offline or @unit.rekey or @unit.transactions.keyreg or @unit.responses or @unit.responses.231 or @unit.tealsign or @unit.transactions or @unit.transactions.payment or @unit.responses.unlimited_assets or @unit.indexer.ledger_refactoring or @unit.algod.ledger_refactoring" unit: behave --tags=$(UNITS) test -f progress2 diff --git a/algosdk/v2client/algod.py b/algosdk/v2client/algod.py index 89513b40..74d96782 100644 --- a/algosdk/v2client/algod.py +++ b/algosdk/v2client/algod.py @@ -93,15 +93,18 @@ def algod_request( else: return resp.read() - def account_info(self, address, **kwargs): + def account_info(self, address, exclude=None, **kwargs): """ Return account information. Args: address (str): account public key """ + query = {} + if exclude: + query["exclude"] = exclude req = "/accounts/" + address - return self.algod_request("GET", req, **kwargs) + return self.algod_request("GET", req, query, **kwargs) def asset_info(self, asset_id, **kwargs): """ @@ -123,6 +126,30 @@ def application_info(self, application_id, **kwargs): req = "/applications/" + str(application_id) return self.algod_request("GET", req, **kwargs) + def account_asset_info(self, address, asset_id, **kwargs): + """ + Return asset information for a specific account. + + Args: + address (str): account public key + asset_id (int): The ID of the asset to look up. + """ + query = {} + req = "/accounts/" + address + "/assets/" + str(asset_id) + return self.algod_request("GET", req, query, **kwargs) + + def account_application_info(self, address, application_id, **kwargs): + """ + Return application information for a specific account. + + Args: + address (str): account public key + application_id (int): The ID of the application to look up. + """ + query = {} + req = "/accounts/" + address + "/applications/" + str(application_id) + return self.algod_request("GET", req, query, **kwargs) + def pending_transactions_by_address( self, address, limit=0, response_format="json", **kwargs ): diff --git a/algosdk/v2client/indexer.py b/algosdk/v2client/indexer.py index 1e54ae2b..f1d0da3a 100644 --- a/algosdk/v2client/indexer.py +++ b/algosdk/v2client/indexer.py @@ -105,6 +105,7 @@ def accounts( application_id=None, round_num=None, include_all=False, + exclude=None, **kwargs ): """ @@ -156,6 +157,8 @@ def accounts( query["application-id"] = application_id if include_all: query["include-all"] = include_all + if exclude: + query["exclude"] = exclude return self.indexer_request("GET", req, query, **kwargs) def asset_balances( @@ -165,8 +168,6 @@ def asset_balances( next_page=None, min_balance=None, max_balance=None, - block=None, - round_num=None, include_all=False, **kwargs ): @@ -208,7 +209,6 @@ def asset_balances( query["currency-less-than"] = max_balance if include_all: query["include-all"] = include_all - _specify_round(query, block, round_num) return self.indexer_request("GET", req, query, **kwargs) def block_info(self, block=None, round_num=None, **kwargs): @@ -227,7 +227,13 @@ def block_info(self, block=None, round_num=None, **kwargs): return self.indexer_request("GET", req, **kwargs) def account_info( - self, address, block=None, round_num=None, include_all=False, **kwargs + self, + address, + block=None, + round_num=None, + include_all=False, + exclude=None, + **kwargs ): """ Return account information. @@ -247,6 +253,178 @@ def account_info( _specify_round(query, block, round_num) if include_all: query["include-all"] = include_all + if exclude: + query["exclude"] = exclude + + return self.indexer_request("GET", req, query, **kwargs) + + def lookup_account_assets( + self, + address, + limit=None, + next_page=None, + asset_id=None, + block=None, + round_num=None, + include_all=False, + **kwargs + ): + """ + Return asset information for a specific account. + + Args: + address (str): account public key + limit (int, optional): maximum number of results to return + next_page (str, optional): the next page of results; use the next + token provided by the previous results + asset_id (int): include transactions for the specified + asset + block (int, optional): use results from the specified round + round_num (int, optional): alias for block; only specify one of + these + include_all (bool, optional): include all items including closed + accounts, deleted applications, destroyed assets, opted-out + asset holdings, and closed-out application localstates. Defaults + to false. + """ + req = "/accounts/" + address + "/assets" + query = dict() + if asset_id: + query["asset-id"] = asset_id + _specify_round(query, block, round_num) + if include_all: + query["include-all"] = "true" + if limit: + query["limit"] = limit + if next_page: + query["next"] = next_page + + return self.indexer_request("GET", req, query, **kwargs) + + def lookup_account_asset_by_creator( + self, + address, + limit=None, + next_page=None, + asset_id=None, + block=None, + round_num=None, + include_all=False, + **kwargs + ): + """ + Return asset information created by a specific account. + + Args: + address (str): account public key + limit (int, optional): maximum number of results to return + next_page (str, optional): the next page of results; use the next + token provided by the previous results + asset_id (int): include transactions for the specified + asset + block (int, optional): use results from the specified round + round_num (int, optional): alias for block; only specify one of + these + include_all (bool, optional): include all items including closed + accounts, deleted applications, destroyed assets, opted-out + asset holdings, and closed-out application localstates. Defaults + to false. + """ + req = "/accounts/" + address + "/created-assets" + query = dict() + if asset_id: + query["asset-id"] = asset_id + _specify_round(query, block, round_num) + if include_all: + query["include-all"] = "true" + if limit: + query["limit"] = limit + if next_page: + query["next"] = next_page + + return self.indexer_request("GET", req, query, **kwargs) + + def lookup_account_application_local_state( + self, + address, + limit=None, + next_page=None, + application_id=None, + block=None, + round_num=None, + include_all=False, + **kwargs + ): + """ + Return application local state for a specific account. + + Args: + address (str): account public key + limit (int, optional): maximum number of results to return + next_page (str, optional): the next page of results; use the next + token provided by the previous results + application_id (int, optional): restrict search to application index + block (int, optional): use results from the specified round + round_num (int, optional): alias for block; only specify one of + these + include_all (bool, optional): include all items including closed + accounts, deleted applications, destroyed assets, opted-out + asset holdings, and closed-out application localstates. Defaults + to false. + """ + req = "/accounts/" + address + "/apps-local-state" + query = dict() + if application_id: + query["application-id"] = application_id + _specify_round(query, block, round_num) + if include_all: + query["include-all"] = "true" + if limit: + query["limit"] = limit + if next_page: + query["next"] = next_page + + return self.indexer_request("GET", req, query, **kwargs) + + def lookup_account_application_by_creator( + self, + address, + limit=None, + next_page=None, + application_id=None, + block=None, + round_num=None, + include_all=False, + **kwargs + ): + """ + Return asset information created by a specific account. + + Args: + address (str): account public key + limit (int, optional): maximum number of results to return + next_page (str, optional): the next page of results; use the next + token provided by the previous results + application_id (int, optional): restrict search to application index + block (int, optional): use results from the specified round + round_num (int, optional): alias for block; only specify one of + these + include_all (bool, optional): include all items including closed + accounts, deleted applications, destroyed assets, opted-out + asset holdings, and closed-out application localstates. Defaults + to false. + """ + req = "/accounts/" + address + "/created-applications" + query = dict() + if application_id: + query["application-id"] = application_id + _specify_round(query, block, round_num) + if include_all: + query["include-all"] = "true" + if limit: + query["limit"] = limit + if next_page: + query["next"] = next_page return self.indexer_request("GET", req, query, **kwargs) @@ -670,6 +848,7 @@ def applications( def search_applications( self, application_id=None, + creator=None, round=None, limit=None, next_page=None, @@ -695,6 +874,8 @@ def search_applications( query = dict() if application_id: query["application-id"] = application_id + if creator: + query["creator"] = creator _specify_round(query, round, round_num) if limit: query["limit"] = limit diff --git a/test/steps/v2_steps.py b/test/steps/v2_steps.py index 569e50d1..2fabcbcb 100644 --- a/test/steps/v2_steps.py +++ b/test/steps/v2_steps.py @@ -294,6 +294,13 @@ def parse_ledger(context, tot, online, roundNum): assert context.response["current_round"] == int(roundNum) +@when( + 'we make an Account Information call against account "{account}" with exclude "{exclude:MaybeString}"' +) +def acc_info(context, account, exclude): + context.response = context.acl.account_info(account, exclude=exclude) + + @when('we make an Account Information call against account "{account}"') def acc_info(context, account): context.response = context.acl.account_info(account) @@ -313,6 +320,22 @@ def parse_acc_info(context, address): assert context.response["address"] == address +@when( + 'we make an Account Asset Information call against account "{account}" assetID {assetID}' +) +def acc_asset_info(context, account, assetID): + context.response = context.acl.account_asset_info(account, assetID) + + +@when( + 'we make an Account Application Information call against account "{account}" applicationID {applicationID}' +) +def acc_application_info(context, account, applicationID): + context.response = context.acl.account_application_info( + account, applicationID + ) + + @when("we make a GetAssetByID call for assetID {asset_id}") def asset_info(context, asset_id): context.response = context.acl.asset_info(int(asset_id)) @@ -408,6 +431,64 @@ def parse_asset_balance( ) +@when( + 'we make a LookupAccountAssets call with accountID "{account}" assetID {asset_id} includeAll "{includeAll:MaybeBool}" limit {limit} next "{next:MaybeString}"' +) +def lookup_account_assets(context, account, asset_id, includeAll, limit, next): + context.response = context.icl.lookup_account_assets( + account, + asset_id=int(asset_id), + include_all=includeAll, + limit=int(limit), + next_page=next, + ) + + +@when( + 'we make a LookupAccountCreatedAssets call with accountID "{account}" assetID {asset_id} includeAll "{includeAll:MaybeBool}" limit {limit} next "{next:MaybeString}"' +) +def lookup_account_created_assets( + context, account, asset_id, includeAll, limit, next +): + context.response = context.icl.lookup_account_asset_by_creator( + account, + asset_id=int(asset_id), + include_all=includeAll, + limit=int(limit), + next_page=next, + ) + + +@when( + 'we make a LookupAccountAppLocalStates call with accountID "{account}" applicationID {application_id} includeAll "{includeAll:MaybeBool}" limit {limit} next "{next:MaybeString}"' +) +def lookup_account_applications( + context, account, application_id, includeAll, limit, next +): + context.response = context.icl.lookup_account_application_local_state( + account, + application_id=int(application_id), + include_all=includeAll, + limit=int(limit), + next_page=next, + ) + + +@when( + 'we make a LookupAccountCreatedApplications call with accountID "{account}" applicationID {application_id} includeAll "{includeAll:MaybeBool}" limit {limit} next "{next:MaybeString}"' +) +def lookup_account_created_applications( + context, account, application_id, includeAll, limit, next +): + context.response = context.icl.lookup_account_application_by_creator( + account, + application_id=int(application_id), + include_all=includeAll, + limit=int(limit), + next_page=next, + ) + + @when("I use {indexer} to search for all {assetid} asset transactions") def icl_asset_txns(context, indexer, assetid): context.response = context.icls[indexer].search_asset_transactions( @@ -788,6 +869,13 @@ def lookup_account(context, account, block): context.response = context.icl.account_info(account, int(block)) +@when( + 'we make a Lookup Account by ID call against account "{account}" with exclude "{exclude:MaybeString}"' +) +def lookup_account(context, account, exclude): + context.response = context.icl.account_info(account, exclude=exclude) + + @when("we make any LookupAccountByID call") def lookup_account_any(context): context.response = context.icl.account_info( @@ -894,6 +982,11 @@ def search_application(context, app_id): context.response = context.icl.search_applications(int(app_id)) +@when('we make a SearchForApplications call with creator "{creator}"') +def search_application(context, creator): + context.response = context.icl.search_applications(creator=creator) + + @when( "we make a Search Accounts call with assetID {index} limit {limit} currencyGreaterThan {currencyGreaterThan} currencyLessThan {currencyLessThan} and round {block}" ) @@ -935,6 +1028,14 @@ def search_accounts( ) +@when('we make a Search Accounts call with exclude "{exclude:MaybeString}"') +def search_accounts( + context, + exclude, +): + context.response = context.icl.accounts(exclude=exclude) + + @when( 'I use {indexer} to search for an account with {assetid}, {limit}, {currencygt}, {currencylt}, "{auth_addr:MaybeString}", {application_id}, "{include_all:MaybeBool}" and token "{token:MaybeString}"' ) From 66660112154f85a17a5ccfd9ec36d28a6236dbbb Mon Sep 17 00:00:00 2001 From: John Lee Date: Thu, 17 Mar 2022 19:51:31 -0400 Subject: [PATCH 3/3] Bumped version to v1.11.0b1 --- CHANGELOG.md | 8 ++++++++ setup.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45452f68..89db140a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +# v1.11.0b1 + +## Added +- Support unlimited assets REST API changes. (#295) + +## Changed +- Fix the cucumber test wording around block rounds in indexer asset balance lookup (#301) + # 1.10.0 ## Added: diff --git a/setup.py b/setup.py index 39ade9ee..759966a3 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ description="Algorand SDK in Python", author="Algorand", author_email="pypiservice@algorand.com", - version="1.10.0", + version="v1.11.0b1", long_description=long_description, long_description_content_type="text/markdown", license="MIT",