From b8ba86db2aa8e11a1bd5a9f26337429281728e1d Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Wed, 15 May 2024 04:27:45 -0400 Subject: [PATCH] Release 0.60.0 --- CHANGELOG.md | 2 +- README.md | 14 +-- pgql_s_example.py | 107 ++++++++++---------- pysui/sui/sui_clients/common.py | 2 +- pysui/sui/sui_pgql/pgql_clients.py | 147 +++++++--------------------- pysui/sui/sui_pgql/pgql_sync_txn.py | 4 +- pysui/sui/sui_pgql/pgql_txb_gas.py | 14 +-- pysui/sui/sui_pgql/pgql_txn_argb.py | 5 +- pysui/sui/sui_pgql/pgql_types.py | 8 +- tests/sui-test/sources/dancer.move | 4 - 10 files changed, 119 insertions(+), 188 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05e64349..fb9f8380 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.60.0] - Unpublished +## [0.60.0] - 2024-05-15 ### Added diff --git a/README.md b/README.md index 6c5e44c6..6bf6f2e5 100644 --- a/README.md +++ b/README.md @@ -19,16 +19,16 @@ Python Client SDK for Sui blockchain **Release-0.60.0** -- Supports _SUI 1.25.x RPC API_ +- Supports _SUI 1.26.x RPC API_ - Backwards compatable to _Sui 1.18.x RPC API_ See [CHANGELOG](https://github.com/FrankC01/pysui/blob/main/CHANGELOG.md) ## PyPi current -**Release-0.59.0 - Released 2024-05-02** +**Release-0.59.0 - Released 2024-05-15** -- Supports _SUI 1.24.x RPC API_ +- Supports _SUI 1.26.x RPC API_ - Backwards compatable to _Sui 1.18.x RPC API_ - [Latest PyPi Version](https://pypi.org/project/pysui/) @@ -46,7 +46,7 @@ Note: MystenLabs/Sui GraphQL RPC is available on devnet, testnet and mainnet [Testnet](https://sui-testnet.mystenlabs.com/graphql) - [Devnet](https://sui-devnet.mystenlabs.com/graphql) + [Devnet](https://sui-devnet.mystenlabs.com/graphql/stable) ### pysui GraphQL support @@ -56,9 +56,9 @@ We continue to monitor and support changes as they evolve. #### Examples - - [Synchronous Client](https://github.com/FrankC01/pysui/blob/v0.57.0/pgql_s_example.py) - Examples for all supported QueryNode queries and mutations - - [Asynchronous Client](https://github.com/FrankC01/pysui/blob/v0.57.0/pgql_a_example.py) - Examples for all supported QueryNode queries and mutations - - [Synchronous TransactionBuilder](https://github.com/FrankC01/pysui/blob/v0.57.0/pgql_s_ptb.py) - Example of new pysui Transaction Builder leveraging Sui GraphQL + - [Synchronous Client](https://github.com/FrankC01/pysui/blob/v0.59.0/pgql_s_example.py) - Examples for all supported QueryNode queries and mutations + - [Asynchronous Client](https://github.com/FrankC01/pysui/blob/v0.59.0/pgql_a_example.py) - Examples for all supported QueryNode queries and mutations + - [Synchronous TransactionBuilder](https://github.com/FrankC01/pysui/blob/v0.59.0/pgql_s_ptb.py) - Example of new pysui Transaction Builder leveraging Sui GraphQL You can read pysui documentation on graphql beta [here](https://pysui.readthedocs.io/en/latest/graphql.html) diff --git a/pgql_s_example.py b/pgql_s_example.py index 3f98ecb5..5d75dbfb 100644 --- a/pgql_s_example.py +++ b/pgql_s_example.py @@ -416,9 +416,9 @@ def do_func(client: SuiGQLClient): """Fetch structures by package::module.""" result = client.execute_query_node( with_node=qn.GetFunction( - package="0x1", - module_name="ascii", - function_name="all_characters_printable", + package="0x3", + module_name="sui_system", + function_name="request_add_stake_mul_coin", ) ) if result.is_ok(): @@ -689,57 +689,60 @@ def do_unstake(client: SuiGQLClient): cfg = SuiConfig.default_config() client_init = SuiGQLClient( - write_schema=False, + write_schema=True, config=cfg, ) print(f"Schema base version {client_init.base_schema_version}") print(f"Schema full version {client_init.schema_version}") - ## QueryNodes (fetch) - # do_coin_meta(client_init) - # do_coins_for_type(client_init) - do_gas(client_init) - # do_all_gas(client_init) - # do_gas_ids(client_init) - # do_sysstate(client_init) - # do_all_balances(client_init) - # do_object(client_init) - # do_objects(client_init) - # do_past_object(client_init) - # do_multiple_past_object(client_init) - # do_objects_for(client_init) - # do_dynamics(client_init) - # do_event(client_init) - # do_tx(client_init) - # do_txs(client_init) - # do_staked_sui(client_init) - # do_latest_cp(client_init) - # do_sequence_cp(client_init) - # do_digest_cp(client_init) - # do_checkpoints(client_init) - # do_nameservice(client_init) - # do_owned_nameservice(client_init) - # do_validators_apy(client_init) - # do_validators(client_init) - # do_refgas(client_init) - # do_struct(client_init) - # do_structs(client_init) - # do_func(client_init) - # do_funcs(client_init) - # do_module(client_init) - # do_package(client_init) - # do_dry_run(client_init) - # do_dry_run_new(client_init) - # do_dry_run_kind_new(client_init) - # do_dry_run_kind(client_init) - # do_execute(client_init) - # do_execute_new(client_init) - # merge_some(client_init) - # split_1_half(client_init) - # do_stake(client_init) - # do_unstake(client_init) - ## Config - # do_chain_id(client_init) - # do_configs(client_init) - # do_service_config(client_init) - # do_protcfg(client_init) + try: + ## QueryNodes (fetch) + # do_coin_meta(client_init) + # do_coins_for_type(client_init) + do_gas(client_init) + # do_all_gas(client_init) + # do_gas_ids(client_init) + # do_sysstate(client_init) + # do_all_balances(client_init) + # do_object(client_init) + # do_objects(client_init) + # do_past_object(client_init) + # do_multiple_past_object(client_init) + # do_objects_for(client_init) + # do_dynamics(client_init) + # do_event(client_init) + # do_tx(client_init) + # do_txs(client_init) + # do_staked_sui(client_init) + # do_latest_cp(client_init) + # do_sequence_cp(client_init) + # do_digest_cp(client_init) + # do_checkpoints(client_init) + # do_nameservice(client_init) + # do_owned_nameservice(client_init) + # do_validators_apy(client_init) + # do_validators(client_init) + # do_refgas(client_init) + # do_struct(client_init) + # do_structs(client_init) + # do_func(client_init) + # do_funcs(client_init) + # do_module(client_init) + # do_package(client_init) + # do_dry_run(client_init) + # do_dry_run_new(client_init) + # do_dry_run_kind_new(client_init) + # do_dry_run_kind(client_init) + # do_execute(client_init) + # do_execute_new(client_init) + # merge_some(client_init) + # split_1_half(client_init) + # do_stake(client_init) + # do_unstake(client_init) + ## Config + # do_chain_id(client_init) + # do_configs(client_init) + # do_service_config(client_init) + # do_protcfg(client_init) + except Exception as ex: + print(ex.args) client_init.client.close_sync() diff --git a/pysui/sui/sui_clients/common.py b/pysui/sui/sui_clients/common.py index 2c488b67..62f564e5 100644 --- a/pysui/sui/sui_clients/common.py +++ b/pysui/sui/sui_clients/common.py @@ -147,7 +147,7 @@ class ClientMixin(Provider): """ _RPC_MINIMAL_VERSION: str = "1.18.0" - _RPC_REQUIRED_VERSION: str = "1.25.0" + _RPC_REQUIRED_VERSION: str = "1.24.0" @versionchanged( version="0.26.1", diff --git a/pysui/sui/sui_pgql/pgql_clients.py b/pysui/sui/sui_pgql/pgql_clients.py index 960ca01b..05a02c23 100644 --- a/pysui/sui/sui_pgql/pgql_clients.py +++ b/pysui/sui/sui_pgql/pgql_clients.py @@ -308,7 +308,8 @@ def __init__( def _execute( self, node: DocumentNode, - schema_constraint: Optional[Union[str, None]], + schema_constraint: Optional[str] = None, + with_headers: Optional[dict] = None, encode_fn: Optional[Callable[[dict], Any]] = None, ) -> SuiRpcResult: """_execute Execute a GQL Document Node @@ -346,6 +347,10 @@ def _execute( "GraphQLSyntaxError", pgql_type.ErrorGQL.from_query(gqe.formatted), ) + except TypeError as te: + return SuiRpcResult( + False, "TypeError", pgql_type.ErrorGQL.from_query(te.args) + ) except ValueError as ve: return SuiRpcResult( False, "ValueError", pgql_type.ErrorGQL.from_query(ve.args) @@ -356,12 +361,15 @@ def execute_query_string( self, *, string: str, - schema_constraint: Optional[Union[str, None]] = None, + schema_constraint: Optional[str] = None, + with_headers: Optional[dict] = None, encode_fn: Optional[Callable[[dict], Any]] = None, ) -> SuiRpcResult: """.""" if isinstance(string, str): - return self._execute(gql(string), schema_constraint, encode_fn) + return self._execute( + gql(string), schema_constraint, with_headers, encode_fn + ) else: return SuiRpcResult(False, "ValueError:Expected string", string) @@ -372,12 +380,13 @@ def execute_document_node( self, *, with_node: DocumentNode, - schema_constraint: Optional[Union[str, None]] = None, + schema_constraint: Optional[str] = None, + with_headers: Optional[dict] = None, encode_fn: Optional[Callable[[dict], Any]] = None, ) -> SuiRpcResult: """.""" if isinstance(with_node, DocumentNode): - return self._execute(with_node, schema_constraint, encode_fn) + return self._execute(with_node, schema_constraint, with_headers, encode_fn) else: return SuiRpcResult(False, "Not a valid gql DocumentNode", with_node) @@ -388,7 +397,8 @@ def execute_query_node( self, *, with_node: PGQL_QueryNode, - schema_constraint: Optional[Union[str, None]] = None, + schema_constraint: Optional[str] = None, + with_headers: Optional[dict] = None, encode_fn: Optional[Callable[[dict], Any]] = None, ) -> SuiRpcResult: """.""" @@ -399,59 +409,12 @@ def execute_query_node( if isinstance(qdoc_node, PGQL_NoOp): return SuiRpcResult(True, None, pgql_type.NoopGQL.from_query()) encode_fn = encode_fn or with_node.encode_fn() - return self._execute(qdoc_node, schema_constraint, encode_fn) + return self._execute(qdoc_node, schema_constraint, with_headers, encode_fn) except ValueError as ve: return SuiRpcResult( False, "ValueError", pgql_type.ErrorGQL.from_query(ve.args) ) - @deprecated( - version="0.56.0", - reason="Use explicit execute for type (str,DocumentNode,PGQL_QueryNode. This will be deleted in version 0.60.0)", - ) - def execute_query( - self, - *, - with_string: Optional[str] = None, - with_document_node: Optional[DocumentNode] = None, - with_query_node: Optional[PGQL_QueryNode] = None, - encode_fn: Optional[Callable[[dict], Any]] = None, - ) -> SuiRpcResult: - """Executes a GraphQL query and returns raw result. - - with_string and with_document_node and with_query_node are mutually exclusive. - with_string takes precedence, then with_document_node then with_query_node. If none is - specific an error is returned. - - :param with_string: A python string query, defaults to None - :type with_string: Optional[str], optional - :param with_document_node: A gql DocumentNode query, defaults to None - :type with_document_node: Optional[DocumentNode], optional - :param with_query_node: A pysui GraphQL QueryNode, defaults to None - :type with_query_node: Optional[PGQL_QueryNode], optional - :param encode_fn: Encoding function taking dict as arg and returning Any, defaults to None - This can be used on any 'with_' option. If used in addition to with_query_node it - will override the builder property of same name if defined - :type encode_fn: Optional[Callable[[dict], Any]], optional - :return: SuiRpcResult cointaining status and raw result (dict) or that defined by serialization function - :rtype: SuiRpcResult - """ - - if with_string: - return self.execute_query_string(string=with_string, encode_fn=encode_fn) - elif with_document_node: - return self.execute_document_node( - with_node=with_document_node, encode_fn=encode_fn - ) - elif with_query_node: - return self.execute_query_node( - with_node=with_query_node, encode_fn=encode_fn - ) - return SuiRpcResult( - False, - "Call requires python str, gql.DocumentNode, or PGQL_QueryNode types", - ) - class AsyncSuiGQLClient(BaseSuiGQLClient): """Asynchronous pysui GraphQL client.""" @@ -505,7 +468,8 @@ def __init__( async def _execute( self, node: DocumentNode, - schema_constraint: Optional[Union[str, None]], + schema_constraint: Optional[str] = None, + with_headers: Optional[dict] = None, encode_fn: Optional[Callable[[dict], Any]] = None, ) -> SuiRpcResult: """_execute Execute a GQL Document Node @@ -544,6 +508,10 @@ async def _execute( "GraphQLSyntaxError", pgql_type.ErrorGQL.from_query(gqe.formatted), ) + except TypeError as te: + return SuiRpcResult( + False, "TypeError", pgql_type.ErrorGQL.from_query(te.args) + ) except ValueError as ve: return SuiRpcResult( False, "ValueError", pgql_type.ErrorGQL.from_query(ve.args) @@ -554,12 +522,15 @@ async def execute_query_string( self, *, string: str, - schema_constraint: Optional[Union[str, None]] = None, + schema_constraint: Optional[str] = None, + with_headers: Optional[dict] = None, encode_fn: Optional[Callable[[dict], Any]] = None, ) -> SuiRpcResult: """.""" if isinstance(string, str): - return await self._execute(gql(string), schema_constraint, encode_fn) + return await self._execute( + gql(string), schema_constraint, with_headers, encode_fn + ) else: return SuiRpcResult(False, "ValueError:Expected string", string) @@ -570,12 +541,15 @@ async def execute_document_node( self, *, with_node: DocumentNode, - schema_constraint: Optional[Union[str, None]] = None, + schema_constraint: Optional[str] = None, + with_headers: Optional[dict] = None, encode_fn: Optional[Callable[[dict], Any]] = None, ) -> SuiRpcResult: """.""" if isinstance(with_node, DocumentNode): - return await self._execute(with_node, schema_constraint, encode_fn) + return await self._execute( + with_node, schema_constraint, with_headers, encode_fn + ) else: return SuiRpcResult(False, "Not a valid gql DocumentNode", with_node) @@ -586,7 +560,8 @@ async def execute_query_node( self, *, with_node: PGQL_QueryNode, - schema_constraint: Optional[Union[str, None]] = None, + schema_constraint: Optional[str] = None, + with_headers: Optional[dict] = None, encode_fn: Optional[Callable[[dict], Any]] = None, ) -> SuiRpcResult: """.""" @@ -597,56 +572,10 @@ async def execute_query_node( if isinstance(qdoc_node, PGQL_NoOp): return SuiRpcResult(True, None, pgql_type.NoopGQL.from_query()) encode_fn = encode_fn or with_node.encode_fn() - return await self._execute(qdoc_node, schema_constraint, encode_fn) + return await self._execute( + qdoc_node, schema_constraint, with_headers, encode_fn + ) except ValueError as ve: return SuiRpcResult( False, "ValueError", pgql_type.ErrorGQL.from_query(ve.args) ) - - @deprecated( - version="0.56.0", - reason="Use explicit execute for type (str,DocumentNode,PGQL_QueryNode. This will be deleted in version 0.60.0)", - ) - async def execute_query( - self, - *, - with_string: Optional[str] = None, - with_document_node: Optional[DocumentNode] = None, - with_query_node: Optional[PGQL_QueryNode] = None, - encode_fn: Optional[Callable[[dict], Any]] = None, - ) -> SuiRpcResult: - """Executes a GraphQL query and returns raw result. - - with_string and with_document_node and with_query_node are mutually exclusive. - with_string takes precedence, then with_document_node then with_query_node. If none is - specific an error is returned. - - :param with_string: A python string query, defaults to None - :type with_string: Optional[str], optional - :param with_document_node: A gql DocumentNode query, defaults to None - :type with_document_node: Optional[DocumentNode], optional - :param with_query_node: A pysui GraphQL QueryNode, defaults to None - :type with_query_node: Optional[PGQL_QueryNode], optional - :param encode_fn: Encode function taking dict as arg and returning Any, defaults to None - This can be used on any 'with_' option. If used in addition to with_query_node it - will override the builder property of same name if defined - :type encode_fn: Optional[Callable[[dict], Any]], optional - :return: Raw result (dict) or type returned defined by serialization function - :rtype: Any - """ - if with_string: - return await self.execute_query_string( - schema_constraint=with_string, encode_fn=encode_fn - ) - elif with_document_node: - return await self.execute_document_node( - with_node=with_document_node, encode_fn=encode_fn - ) - elif with_query_node: - return await self.execute_query_node( - with_node=with_query_node, encode_fn=encode_fn - ) - return SuiRpcResult( - False, - "Call requires python str, gql.DocumentNode, or PGQL_QueryNode types", - ) diff --git a/pysui/sui/sui_pgql/pgql_sync_txn.py b/pysui/sui/sui_pgql/pgql_sync_txn.py index b98cbfc9..05db516a 100644 --- a/pysui/sui/sui_pgql/pgql_sync_txn.py +++ b/pysui/sui/sui_pgql/pgql_sync_txn.py @@ -172,8 +172,8 @@ def _function_meta_args( package, package_module, package_function = ( tv.TypeValidator.check_target_triplet(target) ) - result = self.client.execute_query( - with_query_node=qn.GetFunction( + result = self.client.execute_query_node( + with_node=qn.GetFunction( package=package, module_name=package_module, function_name=package_function, diff --git a/pysui/sui/sui_pgql/pgql_txb_gas.py b/pysui/sui/sui_pgql/pgql_txb_gas.py index ab9fc4ae..ea246828 100644 --- a/pysui/sui/sui_pgql/pgql_txb_gas.py +++ b/pysui/sui/sui_pgql/pgql_txb_gas.py @@ -16,8 +16,8 @@ def _get_gas_objects( client: BaseSuiGQLClient, gas_ids: list[str] ) -> list[pgql_type.SuiCoinObjectGQL]: """Retreive specific Gas Objects.""" - result = client.execute_query( - with_query_node=qn.GetMultipleGasObjects(coin_object_ids=gas_ids) + result = client.execute_query_node( + with_node=qn.GetMultipleGasObjects(coin_object_ids=gas_ids) ) if result.is_ok(): return result.result_data.data @@ -31,13 +31,13 @@ def _get_all_gas_objects( """Retreive all Gas Objects.""" payer = signing.payer_address coin_list: list[pgql_type.SuiCoinObjectGQL] = [] - result = client.execute_query(with_query_node=qn.GetCoins(owner=payer)) + result = client.execute_query_node(with_node=qn.GetCoins(owner=payer)) while True: if result.is_ok(): coin_list.extend(result.result_data.data) if result.result_data.next_cursor.hasNextPage: - result = client.execute_query( - with_query_node=qn.GetCoins( + result = client.execute_query_node( + with_node=qn.GetCoins( owner=payer, next_page=result.result_data.next_cursor ) ) @@ -55,8 +55,8 @@ def _dry_run_for_budget( active_gas_price: int, ) -> int: """Perform a dry run when no budget specified.""" - result = client.execute_query( - with_query_node=qn.DryRunTransactionKind( + result = client.execute_query_node( + with_node=qn.DryRunTransactionKind( tx_bytestr=tx_bytes, tx_meta={ "sender": signing.sender_str, diff --git a/pysui/sui/sui_pgql/pgql_txn_argb.py b/pysui/sui/sui_pgql/pgql_txn_argb.py index cf9fe4ec..05ec6a99 100644 --- a/pysui/sui/sui_pgql/pgql_txn_argb.py +++ b/pysui/sui/sui_pgql/pgql_txn_argb.py @@ -146,8 +146,9 @@ def _scalar_argument( # Validate arg matches expectation if arg: - if _SCALARS.get(expected_type.scalar_type) and not isinstance(arg, int): - raise ValueError(f"Expected int and found {arg.__class__}") + if _SCALARS.get(expected_type.scalar_type): + if not isinstance(arg, int): + raise ValueError(f"Expected int and found {arg.__class__}") elif not isinstance(arg, str): raise ValueError(f"Expected str found {arg.__class__}") diff --git a/pysui/sui/sui_pgql/pgql_types.py b/pysui/sui/sui_pgql/pgql_types.py index 672f50f2..6dd67d36 100644 --- a/pysui/sui/sui_pgql/pgql_types.py +++ b/pysui/sui/sui_pgql/pgql_types.py @@ -1047,9 +1047,11 @@ class MoveFunctionGQL: @classmethod def from_query(clz, in_data: dict) -> "MoveFunctionGQL": - fdict: dict = {} - _fast_flat(in_data, fdict) - return MoveFunctionGQL.from_dict(fdict) + if in_data.get("object"): + fdict: dict = {} + _fast_flat(in_data, fdict) + return MoveFunctionGQL.from_dict(fdict) + return NoopGQL.from_query() def arg_summary(self) -> MoveArgSummary: """Summarize the function's arguments.""" diff --git a/tests/sui-test/sources/dancer.move b/tests/sui-test/sources/dancer.move index a15fb4fe..b97e4eb1 100644 --- a/tests/sui-test/sources/dancer.move +++ b/tests/sui-test/sources/dancer.move @@ -1,9 +1,5 @@ /// Base module for sui module pysuidance::dancer { - use sui::transfer; - use std::vector; - use sui::object::{Self, UID}; - use sui::tx_context::{Self, TxContext}; /// Does not contain value const DoesNotExist: u64 = 2;