From d11923691e3612400dc41677ec027808522165ac Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Mon, 7 Apr 2025 11:02:13 +0300 Subject: [PATCH] update sdk-py cookbook --- .../sdk-py/sdk-py-cookbook-v1.md | 239 +++++++++++++----- scripts/README.md | 7 - 2 files changed, 178 insertions(+), 68 deletions(-) diff --git a/docs/sdk-and-tools/sdk-py/sdk-py-cookbook-v1.md b/docs/sdk-and-tools/sdk-py/sdk-py-cookbook-v1.md index aaf83fd7c..33f623555 100644 --- a/docs/sdk-and-tools/sdk-py/sdk-py-cookbook-v1.md +++ b/docs/sdk-and-tools/sdk-py/sdk-py-cookbook-v1.md @@ -44,7 +44,16 @@ By default, an Entrypoint, in our case the `DevnetEntrypoint`, uses the API, but ```py from multiversx_sdk import DevnetEntrypoint -custom_entrypoint = DevnetEntrypoint(url="https:devnet-gateway.multiversx.com", kind="proxy") +custom_entrypoint = DevnetEntrypoint(url="https://devnet-gateway.multiversx.com", kind="proxy") +``` + +We can create an entrypoint from a network provider. + +```py +from multiversx_sdk import NetworkEntrypoint, ApiNetworkProvider + +api = ApiNetworkProvider("https://devnet-api.multiversx.com") +entrypoint = NetworkEntrypoint.new_from_network_provider(network_provider=api, chain_id="D") ``` ## Creating Accounts @@ -234,6 +243,29 @@ config = NetworkProviderConfig( api = ApiNetworkProvider(url="https://devnet-api.multiversx.com", config=config) ``` +The network providers support a retry mechanism for failing requests. If you'd like to change the default values you can do so as follows: + +```py +from multiversx_sdk import NetworkProviderConfig, ApiNetworkProvider, RequestsRetryOptions + +retry_options = RequestsRetryOptions( + retries=5, + backoff_factor=0.1, + status_forecelist=[500, 502, 503] +) + +config = NetworkProviderConfig( + client_name="hello-multiversx", + requests_options={ + "timeout": 1, + "auth": ("user", "password") + }, + requests_retry_options=retry_options, +) + +api = ApiNetworkProvider(url="https://devnet-api.multiversx.com", config=config) +``` + A list of all the available methods from the `ApiNetworkProviders` can be found [here](https://multiversx.github.io/mx-sdk-py/multiversx_sdk.network_providers.html#module-multiversx_sdk.network_providers.api_network_provider). Both the `ApiNetworkProvider` and the `ProxyNetworkProvider` implement a common interface, that can be seen [here](https://multiversx.github.io/mx-sdk-py/multiversx_sdk.network_providers.html#multiversx_sdk.network_providers.interface.INetworkProvider). Therefore, the two network providers can be used interchangeably. @@ -391,7 +423,6 @@ api = entrypoint.create_network_provider() alice = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") bob = Address.new_from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx") -# this transaction is not signed transaction = Transaction( sender=alice, receiver=bob, @@ -399,7 +430,10 @@ transaction = Transaction( chain_id="D" ) -# the API will return an error because the transaction is not signed +# set correct nonce and sign the transaction +... + +# broadcast the transaction to the network transaction_hash = api.send_transaction(transaction) ``` @@ -414,7 +448,6 @@ api = entrypoint.create_network_provider() alice = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") bob = Address.new_from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx") -# this transaction is not signed first_transaction = Transaction( sender=alice, receiver=bob, @@ -422,6 +455,8 @@ first_transaction = Transaction( chain_id="D", nonce=2 ) +# set correct nonce and sign the transaction +... second_transaction = Transaction( sender=bob, @@ -430,6 +465,8 @@ second_transaction = Transaction( chain_id="D", nonce=1 ) +# set correct nonce and sign the transaction +... third_transaction = Transaction( sender=alice, @@ -439,8 +476,10 @@ third_transaction = Transaction( nonce=3, data=b"hello" ) +# set correct nonce and sign the transaction +... -# the API will return an error because the transactions are not signed +# broadcast the transactions to the network num_of_txs, hashes = api.send_transactions([first_transaction, second_transaction, third_transaction]) ``` @@ -630,7 +669,7 @@ response = api.query_contract(query=query) The methods exposed by the `ApiNetworkProvider` or `ProxyNetworkProvider` are the most common and used ones. There might be times when custom API calls are needed. For that we have createad generic methods for both `GET` and `POST` requests. -Let's assume we want to get all the transactions that are sent by Alice and call the `testFunction` function. +Let's assume we want to get all the transactions that are sent by Alice where the `delegate` function was called. ```py from multiversx_sdk import Address, DevnetEntrypoint @@ -641,7 +680,7 @@ api = entrypoint.create_network_provider() alice = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") url_params = { "sender": alice.to_bech32(), - "function": "testFunction" + "function": "delegate" } transactions = api.do_get_generic(url="transactions", url_parameters=url_params) @@ -711,6 +750,7 @@ If you know you'll only send native tokens, the same transaction can be created Because we only use the address of the sender, the transactions are not going to be signed or have the nonce field set properly. This should be taken care after the transaction is created. ```py +from pathlib import Path from multiversx_sdk import Account, DevnetEntrypoint entrypoint = DevnetEntrypoint() @@ -785,6 +825,8 @@ If you know you'll only send ESDT tokens, the same transaction can be created us Because we only use the address of the sender, the transactions are not going to be signed or have the nonce field set properly. This should be taken care after the transaction is created. ```py +from pathlib import Path + from multiversx_sdk import Account, DevnetEntrypoint, Token, TokenTransfer entrypoint = DevnetEntrypoint() @@ -808,6 +850,7 @@ second_transfer = TokenTransfer(token=nft, amount=1) # when sending NFTs we set sft = Token(identifier="SFT-123987", nonce=10) third_transfer = TokenTransfer(token=nft, amount=7) # for SFTs we set the desired amount we want to send +factory = entrypoint.create_transfers_transactions_factory() transaction = factory.create_transaction_for_transfer( sender=alice.address, receiver=bob, @@ -863,7 +906,7 @@ transaction = transfers_controller.create_transaction_for_transfer( tx_hash = entrypoint.send_transaction(transaction) ``` -#### Decoding transaction data +### Decoding transaction data For example, when sending multiple ESDT and NFT tokens, the receiver field of the transaction is the same as the sender field and also the value is set to `0` because all the information is encoded in the `data` field of the transaction. @@ -881,9 +924,9 @@ decoded_transaction = decoder.get_transaction_metadata(transaction) print(decoded_transaction.to_dict()) ``` -### Smart Contracts +## Smart Contracts -#### Contract ABIs +### Contract ABIs A contract's ABI describes the endpoints, data structure and events that a contract exposes. While contract interactions are possible without the ABI, they are easier to implement when the definitions are available. @@ -1264,12 +1307,14 @@ tx_hash = entrypoint.send_transaction(execute_transaction) print(tx_hash.hex()) ``` -#### Parsing transaction outcome +### Parsing transaction outcome As said before, the `add` endpoint we called does not return anything, but we could parse the outcome of smart contract call transactions, as follows: ```py -from multiversx_sdk import DevnetEntrypoint, SmartContractTransactionsOutcomeParser +from pathlib import Path + +from multiversx_sdk import SmartContractTransactionsOutcomeParser from multiversx_sdk.abi import Abi # load the abi file @@ -1284,7 +1329,7 @@ transaction_on_network = entrypoint.get_transaction(tx_hash) # the tx_hash from outcome = parser.parse_execute(transaction=transaction_on_network, function="add") ``` -#### Decoding transaction events +### Decoding transaction events You might be interested into decoding events emitted by a contract. You can do so by using the `TransactionEventsParser`. @@ -1293,6 +1338,8 @@ Suppose we'd like to decode a `startPerformAction` event emitted by the [multisi First, we load the abi file, then we fetch the transaction, we extract the event from the transaction and then we parse it. ```py +from pathlib import Path + from multiversx_sdk import DevnetEntrypoint, TransactionEventsParser, find_events_by_first_topic from multiversx_sdk.abi import Abi @@ -1313,7 +1360,7 @@ events_parser = TransactionEventsParser(abi=abi) parsed_event = events_parser.parse_event(event) ``` -#### Encoding/Decoding custom types +### Encoding/Decoding custom types Whenever needed, the contract ABI can be used for manually encoding or decoding custom types. @@ -1405,6 +1452,8 @@ When querying a smart contract, a **view function** is called. That function doe To query a smart contract, we need to use the `SmartContractController`. Of course, we can use the contract's abi file to encode the arguments of the query, but also parse the result. In this example, we are going to use the [adder](https://github.com/multiversx/mx-contracts-rs/tree/main/contracts/adder) smart contract and we'll call the `getSum` endpoint. ```py +from pathlib import Path + from multiversx_sdk import Address, DevnetEntrypoint from multiversx_sdk.abi import Abi @@ -1428,6 +1477,8 @@ response = sc_controller.query( If we need more granular control, we can split the process in three steps: create the query, run the query and parse the query response. This does the exact same as the example above. ```py +from pathlib import Path + from multiversx_sdk import Address, DevnetEntrypoint from multiversx_sdk.abi import Abi @@ -1472,6 +1523,9 @@ account = Account.new_from_keystore( password="password", address_index=0 ) + +entrypoint = DevnetEntrypoint() + # the developer is responsible for managing the nonce account.nonce = entrypoint.recall_account_nonce(account.address) @@ -1479,7 +1533,6 @@ account.nonce = entrypoint.recall_account_nonce(account.address) abi = Abi.load(Path("contracts/adder.abi.json")) # get the smart contracts controller -entrypoint = DevnetEntrypoint() controller = entrypoint.create_smart_contract_controller(abi=abi) # load the contract bytecode; this is the new contract code, the one we want to upgrade to @@ -2080,7 +2133,7 @@ tx_hash = entrypoint.send_transaction(transaction) ```py from pathlib import Path -from multiversx_sdk import Account, Address, DevnetEntrypoint +from multiversx_sdk import Account, DevnetEntrypoint # create the entrypoint and the account transactions factory entrypoint = DevnetEntrypoint() @@ -2089,9 +2142,6 @@ factory = entrypoint.create_account_transactions_factory() # create the account to guard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) -# we can use a trusted service that provides a guardian, or simply set another address we own or trust -guardian = Address.new_from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx") - transaction = factory.create_transaction_for_guarding_account( sender=alice.address, ) @@ -2112,27 +2162,31 @@ tx_hash = entrypoint.send_transaction(transaction) ```py from pathlib import Path -from multiversx_sdk import Account, Address, DevnetEntrypoint +from multiversx_sdk import Account, DevnetEntrypoint # create the entrypoint and the account controller entrypoint = DevnetEntrypoint() controller = entrypoint.create_account_controller() -# create the account to guard +# the account to unguard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) # fetch the nonce of the network alice.nonce = entrypoint.recall_account_nonce(alice.address) -guardian = Address.new_from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx") +# the guardian account +guardian = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/bob.pem")) transaction = controller.create_transaction_for_unguarding_account( sender=alice, nonce=alice.get_nonce_then_increment(), - guardian=guardian + guardian=guardian.address ) -# the transaction should also be signed by the guardian before being sent otherwise it won't be executed +# the transaction should also be signed by the guardian before being sent, otherwise it won't be executed +transaction.guardian_signature = guardian.sign_transaction(transaction) + +# broadcast the transaction tx_hash = entrypoint.send_transaction(transaction) ``` @@ -2140,21 +2194,21 @@ tx_hash = entrypoint.send_transaction(transaction) ```py from pathlib import Path -from multiversx_sdk import Account, Address, DevnetEntrypoint +from multiversx_sdk import Account, DevnetEntrypoint # create the entrypoint and the account transactions factory entrypoint = DevnetEntrypoint() factory = entrypoint.create_account_transactions_factory() -# create the account to guard +# the account to unguard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) -# we can use a trusted service that provides a guardian, or simply set another address we own or trust -guardian = Address.new_from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx") +# the guardian account +guardian = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/bob.pem")) transaction = factory.create_transaction_for_unguarding_account( sender=alice.address, - guardian=guardian + guardian=guardian.address ) # fetch the nonce of the network @@ -2167,6 +2221,9 @@ transaction.nonce = alice.get_nonce_then_increment() transaction.signature = alice.sign_transaction(transaction) # the transaction should also be signed by the guardian before being sent otherwise it won't be executed +transaction.guardian_signature = guardian.sign_transaction(transaction) + +# broadcast the transaction tx_hash = entrypoint.send_transaction(transaction) ``` @@ -2255,11 +2312,11 @@ In this section, we are going to create a new delegation contract, get the addre from pathlib import Path from multiversx_sdk import Account, DevnetEntrypoint -# create the entrypoint and the account controller +# create the entrypoint and the delegation controller entrypoint = DevnetEntrypoint() controller = entrypoint.create_delegation_controller() -# create the account to guard +# the owner of the contract alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) # fetch the nonce of the network @@ -2287,11 +2344,11 @@ contract_address = outcome[0].contract_address from pathlib import Path from multiversx_sdk import Account, DevnetEntrypoint, DelegationTransactionsOutcomeParser -# create the entrypoint and the account transactions factory +# create the entrypoint and the delegation transactions factory entrypoint = DevnetEntrypoint() factory = entrypoint.create_delegation_transactions_factory() -# create the account to guard +# the owner of the contract alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) transaction = factory.create_transaction_for_new_delegation_contract( @@ -2331,11 +2388,11 @@ We can send funds to a delegation contract to earn rewards. from pathlib import Path from multiversx_sdk import Account, Address, DevnetEntrypoint -# create the entrypoint and the account controller +# create the entrypoint and the delegation controller entrypoint = DevnetEntrypoint() controller = entrypoint.create_delegation_controller() -# create the account to guard +# create the account delegating funds alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) # fetch the nonce of the network @@ -2360,11 +2417,11 @@ tx_hash = entrypoint.send_transaction(transaction) from pathlib import Path from multiversx_sdk import Account, DevnetEntrypoint -# create the entrypoint and the account transactions factory +# create the entrypoint and the delegation transactions factory entrypoint = DevnetEntrypoint() factory = entrypoint.create_delegation_transactions_factory() -# create the account to guard +# create the account delegating funds alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) transaction = factory.create_transaction_for_delegating( @@ -2394,11 +2451,10 @@ After a period of time, we might have enough rewards that we want to redelegate from pathlib import Path from multiversx_sdk import Account, Address, DevnetEntrypoint -# create the entrypoint and the account controller +# create the entrypoint and the delegation controller entrypoint = DevnetEntrypoint() controller = entrypoint.create_delegation_controller() -# create the account to guard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) # fetch the nonce of the network @@ -2422,11 +2478,10 @@ tx_hash = entrypoint.send_transaction(transaction) from pathlib import Path from multiversx_sdk import Account, DevnetEntrypoint -# create the entrypoint and the account transactions factory +# create the entrypoint and the delegation transactions factory entrypoint = DevnetEntrypoint() factory = entrypoint.create_delegation_transactions_factory() -# create the account to guard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) transaction = factory.create_transaction_for_redelegating_rewards( @@ -2455,11 +2510,10 @@ We can also claim our rewards. from pathlib import Path from multiversx_sdk import Account, Address, DevnetEntrypoint -# create the entrypoint and the account controller +# create the entrypoint and the delegation controller entrypoint = DevnetEntrypoint() controller = entrypoint.create_delegation_controller() -# create the account to guard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) # fetch the nonce of the network @@ -2483,11 +2537,10 @@ tx_hash = entrypoint.send_transaction(transaction) from pathlib import Path from multiversx_sdk import Account, DevnetEntrypoint -# create the entrypoint and the account transactions factory +# create the entrypoint and the delegation transactions factory entrypoint = DevnetEntrypoint() factory = entrypoint.create_delegation_transactions_factory() -# create the account to guard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) transaction = factory.create_transaction_for_claiming_rewards( @@ -2516,11 +2569,10 @@ By undelegating we let the contract know we want to get back our staked funds. T from pathlib import Path from multiversx_sdk import Account, Address, DevnetEntrypoint -# create the entrypoint and the account controller +# create the entrypoint and the delegation controller entrypoint = DevnetEntrypoint() controller = entrypoint.create_delegation_controller() -# create the account to guard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) # fetch the nonce of the network @@ -2545,11 +2597,10 @@ tx_hash = entrypoint.send_transaction(transaction) from pathlib import Path from multiversx_sdk import Account, DevnetEntrypoint -# create the entrypoint and the account transactions factory +# create the entrypoint and the delegation transactions factory entrypoint = DevnetEntrypoint() factory = entrypoint.create_delegation_transactions_factory() -# create the account to guard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) transaction = factory.create_transaction_for_undelegating( @@ -2579,11 +2630,10 @@ After the unbonding period has passed, we can withdraw our funds from the contra from pathlib import Path from multiversx_sdk import Account, Address, DevnetEntrypoint -# create the entrypoint and the account controller +# create the entrypoint and the delegation controller entrypoint = DevnetEntrypoint() controller = entrypoint.create_delegation_controller() -# create the account to guard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) # fetch the nonce of the network @@ -2607,11 +2657,10 @@ tx_hash = entrypoint.send_transaction(transaction) from pathlib import Path from multiversx_sdk import Account, DevnetEntrypoint -# create the entrypoint and the account transactions factory +# create the entrypoint and the delegation transactions factory entrypoint = DevnetEntrypoint() factory = entrypoint.create_delegation_transactions_factory() -# create the account to guard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) transaction = factory.create_transaction_for_withdrawing( @@ -2640,9 +2689,7 @@ We are currently on the third iteration of relayed transactions. V1 and V2 are s from pathlib import Path from multiversx_sdk import Account, Address, DevnetEntrypoint, Transaction -# create the account to guard alice = Account.new_from_pem(Path("../multiversx_sdk/testutils/testwallets/alice.pem")) - bob = Address.new_from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx") # carol will be our relayer, that means she is paying the gas for the transaction @@ -2908,7 +2955,7 @@ address = factory.create_from_hex("0139472eff6886771a982f3083da5d421f24c29181e63 address = factory.create_from_public_key(bytes.fromhex("0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1")) ``` -#### Getting the shard of an address +### Getting the shard of an address ```py from multiversx_sdk import Address, AddressComputer @@ -2919,7 +2966,7 @@ address = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3 print("Shard:", address_computer.get_shard_of_address(address)) ``` -#### Checking if the address is a smart contract address +### Checking if the address is a smart contract address ```py from multiversx_sdk import Address @@ -2951,7 +2998,7 @@ LibraryConfig.default_address_hrp = "erd" ## Wallets -#### Generating a mnemonic +### Generating a mnemonic Mnemonic generation is based on [`trezor/python-mnemonic`](https://github.com/trezor/python-mnemonic) and can be achieved as follows: @@ -2964,7 +3011,7 @@ words = mnemonic.get_words() print(words) ``` -#### Saving the mnemonic to a keystore file +### Saving the mnemonic to a keystore file The mnemonic can be saved to a keystore file: @@ -3031,7 +3078,7 @@ pem = UserPEM(label=label, secret_key=secret_key) pem.save(Path("wallet.pem")) ``` -#### Generating a KeyPair +### Generating a KeyPair A `KeyPair` is a wrapper over a secret key and a public key. We can create a keypair and use it for signing or verifying. @@ -3047,7 +3094,7 @@ secret_key = keypair.get_secret_key() public_key = keypair.get_public_key() ``` -#### Loading a wallets from keystore mnemonic file +### Loading a wallets from keystore mnemonic file Load a keystore that holds an _encrypted mnemonic_ (and perform wallet derivation at the same time): @@ -3376,6 +3423,76 @@ is_signed_by_alice = public_key.verify(message_computer.compute_bytes_for_verify print("Is signed by Alice:", is_signed_by_alice) ``` +## Generating a Native Auth Token + +The sdk implements a native auth client that can be used to generate a native auth token. + +```py +from pathlib import Path + +from multiversx_sdk import Account, Message, NativeAuthClient, NativeAuthClientConfig + +config = NativeAuthClientConfig(origin="https://devnet-api.multiversx.com", api_url="https://devnet-api.multiversx.com") +client = NativeAuthClient(config) + +account = Account.new_from_keystore( + file_path=Path("../multiversx_sdk/testutils/testwallets/withDummyMnemonic.json"), + password="password", + address_index=0 +) + +init_token = client.initialize() +token_for_signing = client.get_token_for_signing(account.address, init_token) +signature = account.sign_message(Message(token_for_signing)) +access_token = client.get_token(address=account.address, token=init_token, signature=signature.hex()) + +print(access_token) +``` + +## Validating a Native Auth Token + +The sdk implements native auth server-side components that can be used to validate a native auth token. If you want to see the validated token, you can simply do the following: + +```py +from multiversx_sdk import NativeAuthServerConfig, NativeAuthServer + +config = config = NativeAuthServerConfig( + api_url="https://devnet-api.multiversx.com", + accepted_origins=["https://devnet-api.multiversx.com"], + max_expiry_seconds=86400, +) + +server = NativeAuthServer(config) + +# we are using the token generated above +validated_token = server.validate(access_token) + +print(validated_token.address.to_bech32()) +print(validated_token.signer_address.to_bech32()) +print(validated_token.issued) +print(validated_token.expires) +print(validated_token.origin) +print(validated_token.extra_info) +``` + +Or, alternatively, if you just want to check if the token is valid, you can do the following: + +```py +from multiversx_sdk import NativeAuthServerConfig, NativeAuthServer + +config = config = NativeAuthServerConfig( + api_url="https://devnet-api.multiversx.com", + accepted_origins=["https://devnet-api.multiversx.com"], + max_expiry_seconds=86400, +) + +server = NativeAuthServer(config) + +# we are using the token generated above +is_valid = server.is_valid(access_token) +print(is_valid) +``` + ## Start your first project We recommend using a Python version equal to `3.11` or higher, but the sdk should work with any version higher than `3.8`. We also recommend using a virtual environment for managing dependencies. Make sure you also have `pip` installed on your machine. diff --git a/scripts/README.md b/scripts/README.md index 828c6f42d..76b3d131a 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -5,13 +5,6 @@ cd mx-docs python3 ./scripts/render_notebooks.py ``` -## Render file includes - -``` -cd mx-docs -python3 ./scripts/render_includes.py -``` - ## Add bot markers ```