genlayer-test 0.2.0__py3-none-any.whl → 0.3.1__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.
Files changed (43) hide show
  1. {genlayer_test-0.2.0.dist-info → genlayer_test-0.3.1.dist-info}/METADATA +77 -10
  2. genlayer_test-0.3.1.dist-info/RECORD +65 -0
  3. {genlayer_test-0.2.0.dist-info → genlayer_test-0.3.1.dist-info}/entry_points.txt +1 -1
  4. gltest/__init__.py +4 -4
  5. gltest/artifacts/contract.py +9 -4
  6. gltest/glchain/__init__.py +3 -3
  7. gltest/glchain/account.py +15 -11
  8. gltest/glchain/client.py +39 -3
  9. gltest/glchain/contract.py +57 -26
  10. gltest/helpers/fixture_snapshot.py +3 -2
  11. gltest_cli/config/__init__.py +0 -0
  12. gltest_cli/config/constants.py +10 -0
  13. gltest_cli/config/general.py +10 -0
  14. gltest_cli/config/plugin.py +102 -0
  15. gltest_cli/config/types.py +137 -0
  16. gltest_cli/config/user.py +222 -0
  17. gltest_cli/logging.py +51 -0
  18. tests/__init__.py +0 -0
  19. tests/examples/tests/test_llm_erc20.py +2 -2
  20. tests/examples/tests/test_multi_read_erc20.py +13 -3
  21. tests/examples/tests/test_multi_tenant_storage.py +12 -3
  22. tests/examples/tests/test_read_erc20.py +2 -2
  23. tests/examples/tests/test_storage.py +4 -2
  24. tests/examples/tests/test_user_storage.py +17 -3
  25. tests/gltest/__init__.py +0 -0
  26. tests/gltest/artifact/__init__.py +0 -0
  27. tests/gltest/artifact/test_contract_definition.py +91 -0
  28. tests/gltest_cli/__init__.py +0 -0
  29. tests/gltest_cli/config/test_plugin.py +127 -0
  30. tests/gltest_cli/config/test_user.py +351 -0
  31. genlayer_test-0.2.0.dist-info/RECORD +0 -55
  32. gltest/plugin_config.py +0 -42
  33. gltest/plugin_hooks.py +0 -51
  34. tests/artifact/test_contract_definition.py +0 -347
  35. tests/plugin/test_plugin_hooks.py +0 -78
  36. {genlayer_test-0.2.0.dist-info → genlayer_test-0.3.1.dist-info}/WHEEL +0 -0
  37. {genlayer_test-0.2.0.dist-info → genlayer_test-0.3.1.dist-info}/licenses/LICENSE +0 -0
  38. {genlayer_test-0.2.0.dist-info → genlayer_test-0.3.1.dist-info}/top_level.txt +0 -0
  39. /tests/{plugin/conftest.py → conftest.py} +0 -0
  40. /tests/{artifact → gltest/artifact}/contracts/duplicate_ic_contract_1.py +0 -0
  41. /tests/{artifact → gltest/artifact}/contracts/duplicate_ic_contract_2.py +0 -0
  42. /tests/{artifact → gltest/artifact}/contracts/not_ic_contract.py +0 -0
  43. /tests/{assertions → gltest/assertions}/test_assertions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genlayer-test
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Summary: GenLayer Testing Suite
5
5
  Author: GenLayer
6
6
  License-Expression: MIT
@@ -14,7 +14,11 @@ Requires-Python: >=3.12
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
16
  Requires-Dist: pytest
17
- Requires-Dist: genlayer-py==0.3.0
17
+ Requires-Dist: setuptools>=77.0
18
+ Requires-Dist: genlayer-py==0.6.1
19
+ Requires-Dist: colorama>=0.4.6
20
+ Requires-Dist: pyyaml
21
+ Requires-Dist: python-dotenv
18
22
  Dynamic: license-file
19
23
 
20
24
  # GenLayer Testing Suite
@@ -41,13 +45,13 @@ pip install genlayer-test
41
45
  ### Basic Usage
42
46
 
43
47
  ```python
44
- from gltest import get_contract_factory, default_account, create_account
48
+ from gltest import get_contract_factory, get_default_account, create_account
45
49
  from gltest.assertions import tx_execution_succeeded
46
50
 
47
51
  factory = get_contract_factory("MyContract")
48
52
  # Deploy a contract with default account
49
53
  contract = factory.deploy() # This will be deployed with default_account
50
- assert contract.account == default_account
54
+ assert contract.account == get_default_account()
51
55
 
52
56
  # Deploy a contract with other account
53
57
  other_account = create_account()
@@ -99,6 +103,58 @@ $ cd genlayer-testing-suite
99
103
  $ pip install -e .
100
104
  ```
101
105
 
106
+ ### Configuration
107
+
108
+ The GenLayer Testing Suite can be configured using an optional but recommended `gltest.config.yaml` file in your project root. While not required, this file helps manage network configurations, contract paths, and environment settings in a centralized way, making it easier to maintain different environments and share configurations across team members.
109
+
110
+ ```yaml
111
+ # gltest.config.yaml
112
+ networks:
113
+ default: localnet # Default network to use
114
+
115
+ localnet: # Local development network configuration
116
+ url: "http://127.0.0.1:4000/api"
117
+
118
+ testnet_asimov: # Test network configuration
119
+ id: 4221
120
+ url: "http://34.32.169.58:9151"
121
+ accounts:
122
+ - "${ACCOUNT_PRIVATE_KEY_1}"
123
+ - "${ACCOUNT_PRIVATE_KEY_2}"
124
+ - "${ACCOUNT_PRIVATE_KEY_3}"
125
+
126
+ paths:
127
+ contracts: "contracts" # Path to your contracts directory
128
+
129
+ environment: .env # Path to your environment file containing private keys and other secrets
130
+ ```
131
+
132
+ Key configuration sections:
133
+
134
+ 1. **Networks**: Define different network environments
135
+ - `default`: Specifies which network to use by default
136
+ - Network configurations can include:
137
+ - `url`: The RPC endpoint for the network
138
+ - `id`: Chain ID
139
+ - `accounts`: List of account private keys (using environment variables)
140
+ - Special case for `localnet`:
141
+ - If a network is named `localnet`, missing fields will be filled with default values
142
+ - For all other network names, `id`, `url`, and `accounts` are required fields
143
+
144
+ 2. **Paths**: Define important directory paths
145
+ - `contracts`: Location of your contract files
146
+
147
+ 3. **Environment**: Path to your `.env` file containing sensitive information like private keys
148
+
149
+ If you don't provide a config file, the suite will use default values. You can override these settings using command-line arguments. For example:
150
+ ```bash
151
+ # Override the default network
152
+ gltest --network testnet_asimov
153
+
154
+ # Override the contracts directory
155
+ gltest --contracts-dir custom/contracts/path
156
+ ```
157
+
102
158
  ### Running Tests
103
159
 
104
160
  1. Run all tests:
@@ -126,17 +182,27 @@ $ gltest -v
126
182
  $ gltest --contracts-dir <path_to_contracts>
127
183
  ```
128
184
 
129
- 6. Run tests with a custom RPC url
185
+ 6. Run tests on a specific network:
186
+ ```bash
187
+ # Run tests on localnet (default)
188
+ $ gltest --network localnet
189
+
190
+ # Run tests on testnet
191
+ $ gltest --network testnet_asimov
192
+ ```
193
+ The `--network` flag allows you to specify which network configuration to use from your `gltest.config.yaml`. If not specified, it will use the `default` network defined in your config file.
194
+
195
+ 7. Run tests with a custom RPC url
130
196
  ```bash
131
197
  $ gltest --rpc-url <custom_rpc_url>
132
198
  ```
133
199
 
134
- 6. Run tests with a default wait interval for waiting transaction receipts
200
+ 8. Run tests with a default wait interval for waiting transaction receipts
135
201
  ```bash
136
202
  $ gltest --default-wait-interval <default_wait_interval>
137
203
  ```
138
204
 
139
- 6. Run tests with a default wait retries for waiting transaction receipts
205
+ 9. Run tests with a default wait retries for waiting transaction receipts
140
206
  ```bash
141
207
  $ gltest --default-wait-retries <default_wait_retries>
142
208
  ```
@@ -233,13 +299,14 @@ def test_deployment():
233
299
  Reading from the contract is straightforward:
234
300
 
235
301
  ```python
236
- from gltest import get_contract_factory, default_account
302
+ from gltest import get_contract_factory
237
303
 
238
304
  def test_read_methods():
305
+
239
306
  # Get the contract factory and deploy the contract
240
307
  factory = get_contract_factory("Storage")
241
- contract = factory.deploy(account=default_account)
242
-
308
+ contract = factory.deploy()
309
+
243
310
  # Call a read-only method
244
311
  result = contract.get_value(args=[])
245
312
 
@@ -0,0 +1,65 @@
1
+ genlayer_test-0.3.1.dist-info/licenses/LICENSE,sha256=che_H4vE0QUx3HvWrAa1_jDEVInift0U6VO15-QqEls,1064
2
+ gltest/__init__.py,sha256=Uozr4VS-_oKUxEdXbWoEVLB8JQKBWGs6vGEHDj1-6LY,348
3
+ gltest/assertions.py,sha256=0dEk0VxcHK4I7GZPHxJmz-2jaA60V499gOSR74rZbfM,1748
4
+ gltest/exceptions.py,sha256=deJPmrTe5gF33qkkKF2IVJY7lc_knI7Ql3N7jZ8aLZs,510
5
+ gltest/types.py,sha256=BODmwTr2gAUEiO9FjiuTiWwuKvXgo4xZWstQWNUfnlw,156
6
+ gltest/artifacts/__init__.py,sha256=qTt3TE19gVNWnQLUlt5aDe4nNvJ2YJ1jzDkMmYIsCG0,194
7
+ gltest/artifacts/contract.py,sha256=KChpmfjZod_0dVB8y-dvWz6IVm7QlIJsgG2ArtvVDaU,6457
8
+ gltest/glchain/__init__.py,sha256=QLd55hVB9xVTAtCKbjmGPAwh0M8_tUNJ5xI0H93YyTY,428
9
+ gltest/glchain/account.py,sha256=HUmWguJMolggQaZNRPw-LGlRlQCjLLdUanKRowMv6pI,812
10
+ gltest/glchain/client.py,sha256=urRvnLt8GpdCV3yOBSvJNZQzu_TsZr8HqKn14Q2SpIQ,1547
11
+ gltest/glchain/contract.py,sha256=RFLbEZseWatX0Xvt3-Eo_zOowxLMhukoXjK8V8Ca0Ok,11370
12
+ gltest/helpers/__init__.py,sha256=I7HiTu_H7_hP65zY6Wl02r-5eAMr2eZvqBVmusuQLX4,180
13
+ gltest/helpers/fixture_snapshot.py,sha256=VydrtviG60ukSFIvzO5QwK-SHmkRmbsQFEVdyItvGWI,2142
14
+ gltest/helpers/take_snapshot.py,sha256=eXqEKXM2hcox3pLGIcNddobU8zXPQvD-Iwf87eHqW2s,1276
15
+ gltest_cli/logging.py,sha256=2Bkh6OR5C19HefARLQN5xBfam3apXzf7_Wei2PBfKlM,1241
16
+ gltest_cli/main.py,sha256=Ti2-0Ev1x5_cM0D1UKqdgaDt80CDHEQGtdRne2qLm4M,53
17
+ gltest_cli/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ gltest_cli/config/constants.py,sha256=lX8C3aS7zXWazA8LWgE0BkPvy7NopyEMyJNI2yYWX9M,300
19
+ gltest_cli/config/general.py,sha256=ezpoGsT8grO9zQH6RugV14b1GzeFt-htYToHQBJhNvY,186
20
+ gltest_cli/config/plugin.py,sha256=zEWsi18hEoK9yloKKPd8y77wXCpgWf7hAWI1JL8S5Ho,3325
21
+ gltest_cli/config/types.py,sha256=R5ylpHKzoOK43_tXC047mJqAybCZhj615_FWBhsmNAU,5237
22
+ gltest_cli/config/user.py,sha256=LjjoqXWRLPeNgOvLKy2tJDNl1M0uLb-5rwEsnGyJunE,8065
23
+ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ tests/conftest.py,sha256=RKdoE5_zcMimeojAoA_GSFI9du4pMzMi1vZ1njtfoAs,28
25
+ tests/examples/contracts/football_prediction_market.py,sha256=kdouFijjeCdIJyaVJlgXcqbBAXecA9_YdhklSsIW-QM,3219
26
+ tests/examples/contracts/intelligent_oracle.py,sha256=WrNZWWoi1sz22Azt2EXgdWHDg5Ihca2pWUHrM9pVfQE,12319
27
+ tests/examples/contracts/intelligent_oracle_factory.py,sha256=ax496IZuDCA728rRcbjwTaM4Q4E-Y1jGkHsEcyf1cig,1490
28
+ tests/examples/contracts/llm_erc20.py,sha256=nfIs-7A79L46NgHQzWbPyEOUlzAlFLsf4K05acwKr_M,2523
29
+ tests/examples/contracts/log_indexer.py,sha256=VwMC8_Gy1Z1qjuy5GeEMyepjZ3Z5y7VAOrHMl5MrjxI,1852
30
+ tests/examples/contracts/multi_read_erc20.py,sha256=HsMJKGT9a9eZAO43Em7hCRfh1yyHDgcUbQ0gmOE1MXs,850
31
+ tests/examples/contracts/multi_tenant_storage.py,sha256=aGLPC76FegXdnIjMjeGsu3s3AbKK9dtV6t1d_KoI8rI,1897
32
+ tests/examples/contracts/read_erc20.py,sha256=kstiB93JHHajJe1GldzeawxnVYutjT8KE2d1bYTgggU,390
33
+ tests/examples/contracts/storage.py,sha256=GZHBXhjc94eEkdSO1UWgcop0fEo0hD57KZM0ds3pUFM,490
34
+ tests/examples/contracts/user_storage.py,sha256=j-RXxTIqb1dePYqP_pkeoCxxDq07VURryvzF_Q-sZmI,638
35
+ tests/examples/contracts/wizard_of_coin.py,sha256=BJ0Nv6N-JJP_Pk7YUSXPPRxX5_mDRBDlfL6nabeaoyA,1606
36
+ tests/examples/contracts/multi_file_contract/__init__.py,sha256=8O3BvoUrLSmc4uTf2jm7MyrmcaiGD0w8wPwotdAqZHQ,485
37
+ tests/examples/contracts/multi_file_contract/other.py,sha256=jHDtjUL3eAUgE6yOYKFw_RfAH7kIwk8CvxUjbWHNruk,236
38
+ tests/examples/tests/test_football_prediction_market.py,sha256=wFu024sq3IURLL1zyLyO_G1sRCjPTV7iImi87__dZ4Y,657
39
+ tests/examples/tests/test_intelligent_oracle_factory.py,sha256=Nw7jO9bjD79AETT2QQl0Vun-yxSAAuqGSdkQn2Y3WUw,5377
40
+ tests/examples/tests/test_llm_erc20.py,sha256=3-wsZi23TpQ_9HYPfcbyo9206AkDndqTfBzRWXzlsNE,1400
41
+ tests/examples/tests/test_log_indexer.py,sha256=Km44SiA8dlA4WBqwugXVBCQUlODdf1dB4p4nt24HG9k,2649
42
+ tests/examples/tests/test_multi_file_contract.py,sha256=pWmK6lcZrSAnDH09Z6Q-cXs8V6VGFhHkvgThvJKEB4U,512
43
+ tests/examples/tests/test_multi_file_contract_legacy.py,sha256=Jx_u0rDrQJspQgFo1KUddcFgTcOhcE-YLuLgk3tKrCA,527
44
+ tests/examples/tests/test_multi_read_erc20.py,sha256=A-mRoZPj3_0B6CUnwtPFxtXoOfd1RuB8PIeExniZlCs,3411
45
+ tests/examples/tests/test_multi_tenant_storage.py,sha256=yliqhit7wWO1Y6OXl_cv3ruTCOto8ZfKGtkT3lRvZpQ,2717
46
+ tests/examples/tests/test_read_erc20.py,sha256=9bUmigPab2dDf1GElRXVbf1TVbMur37IPT7HFZDmFUg,1208
47
+ tests/examples/tests/test_storage.py,sha256=jcVNAeBynn70Ov1rF1robZwFZptuNLtHW-u1XfG393k,712
48
+ tests/examples/tests/test_storage_legacy.py,sha256=RNVnD0G9ilb4I2s0CPAAgJEuKUgEkkbItuesOfmv-pg,677
49
+ tests/examples/tests/test_user_storage.py,sha256=qUv57rn1X3wAiIglnj3LH3r2clIBwF38MMkKvU4IGaA,2552
50
+ tests/examples/tests/test_wizard_of_coin.py,sha256=aUDeV5w0XONMMS71Vzw80lHfcSM0z8RKPJSXAuDwRto,392
51
+ tests/gltest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
+ tests/gltest/artifact/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
+ tests/gltest/artifact/test_contract_definition.py,sha256=6R8THNFKKpG7brULzp63vT1_pPd_JFNp3ZS08CJJWrg,3642
54
+ tests/gltest/artifact/contracts/duplicate_ic_contract_1.py,sha256=bSWsUVjBy5cGtI72cjnkstsMzuUJbB3IG5JjTxOF-dc,500
55
+ tests/gltest/artifact/contracts/duplicate_ic_contract_2.py,sha256=bSWsUVjBy5cGtI72cjnkstsMzuUJbB3IG5JjTxOF-dc,500
56
+ tests/gltest/artifact/contracts/not_ic_contract.py,sha256=hQyGnYiiVceYdLI2WrvcFgPqzy1S4-YMb9FPhiHEGSA,510
57
+ tests/gltest/assertions/test_assertions.py,sha256=qzVrOdOM4xYtIy1sFHVAD_-naDHOequ23tEN0MELh0k,10781
58
+ tests/gltest_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
+ tests/gltest_cli/config/test_plugin.py,sha256=06-GENVugrL6mPQkgRgQqRsCTuQMy3WZcbh_9Du6zHo,3502
60
+ tests/gltest_cli/config/test_user.py,sha256=oJDcM6NbA16tQzQj5s8ZDvQYBm2uuvar5junFcVeitY,12116
61
+ genlayer_test-0.3.1.dist-info/METADATA,sha256=zW6QEyxquLwgMY9UJb9kVq9MHtxgqcnyAY8Nm9avV4M,17231
62
+ genlayer_test-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
63
+ genlayer_test-0.3.1.dist-info/entry_points.txt,sha256=RWPcSArBpz_G4BYioh5L8Q8hyClRbSgzLimjcWMp-BQ,94
64
+ genlayer_test-0.3.1.dist-info/top_level.txt,sha256=-qiGZxTRBytujzgVcKpxjvQ-WNeUDjXa59ceGMwMpko,24
65
+ genlayer_test-0.3.1.dist-info/RECORD,,
@@ -2,4 +2,4 @@
2
2
  gltest = gltest_cli.main:main
3
3
 
4
4
  [pytest11]
5
- gltest = gltest.plugin_hooks
5
+ gltest = gltest_cli.config.plugin
gltest/__init__.py CHANGED
@@ -3,8 +3,8 @@ from gltest.glchain import (
3
3
  create_accounts,
4
4
  get_contract_factory,
5
5
  get_gl_client,
6
- default_account,
7
- accounts,
6
+ get_accounts,
7
+ get_default_account,
8
8
  )
9
9
 
10
10
  __all__ = [
@@ -13,6 +13,6 @@ __all__ = [
13
13
  "create_accounts",
14
14
  "get_contract_factory",
15
15
  "get_gl_client",
16
- "default_account",
17
- "accounts",
16
+ "get_accounts",
17
+ "get_default_account",
18
18
  ]
@@ -2,7 +2,7 @@ import ast
2
2
  from typing import Optional
3
3
  from dataclasses import dataclass
4
4
  from pathlib import Path
5
- from gltest.plugin_config import get_contracts_dir
5
+ from gltest_cli.config.general import get_general_config
6
6
  import io
7
7
  import zipfile
8
8
  from typing import Union
@@ -21,9 +21,12 @@ class ContractDefinition:
21
21
  def search_path_by_class_name(contracts_dir: Path, contract_name: str) -> Path:
22
22
  """Search for a file by class name in the contracts directory."""
23
23
  matching_files = []
24
+ exclude_dirs = {".venv", "venv", "env", "build", "dist", "__pycache__", ".git"}
24
25
 
25
26
  for file_path in contracts_dir.rglob("*"):
26
- if not file_path.suffix in [".gpy", ".py"]:
27
+ if any(exclude_dir in file_path.parts for exclude_dir in exclude_dirs):
28
+ continue
29
+ if file_path.suffix not in [".gpy", ".py"]:
27
30
  continue
28
31
  try:
29
32
  # Read the file content
@@ -142,7 +145,8 @@ def find_contract_definition_from_name(
142
145
  """
143
146
  Search in the contracts directory for a contract definition.
144
147
  """
145
- contracts_dir = get_contracts_dir()
148
+ general_config = get_general_config()
149
+ contracts_dir = general_config.get_contracts_dir()
146
150
  if not contracts_dir.exists():
147
151
  raise FileNotFoundError(f"Contracts directory not found at: {contracts_dir}")
148
152
 
@@ -156,7 +160,8 @@ def find_contract_definition_from_path(
156
160
  """
157
161
  Create a ContractDefinition from a given file path relative to the contracts directory.
158
162
  """
159
- contracts_dir = get_contracts_dir()
163
+ general_config = get_general_config()
164
+ contracts_dir = general_config.get_contracts_dir()
160
165
  if not contracts_dir.exists():
161
166
  raise FileNotFoundError(f"Contracts directory not found at: {contracts_dir}")
162
167
 
@@ -1,6 +1,6 @@
1
1
  from .contract import Contract, ContractFactory, get_contract_factory
2
2
  from .client import get_gl_client, get_gl_provider
3
- from .account import create_accounts, create_account, accounts, default_account
3
+ from .account import create_account, get_accounts, get_default_account, create_accounts
4
4
 
5
5
 
6
6
  __all__ = [
@@ -8,9 +8,9 @@ __all__ = [
8
8
  "ContractFactory",
9
9
  "get_contract_factory",
10
10
  "create_account",
11
- "default_account",
12
- "accounts",
13
11
  "create_accounts",
12
+ "get_accounts",
13
+ "get_default_account",
14
14
  "get_gl_client",
15
15
  "get_gl_provider",
16
16
  ]
gltest/glchain/account.py CHANGED
@@ -1,18 +1,22 @@
1
+ from gltest_cli.config.general import get_general_config
1
2
  from genlayer_py import create_account
3
+ from eth_account.signers.local import LocalAccount
4
+ from typing import List
2
5
 
3
6
 
4
7
  def create_accounts(n_accounts: int):
5
- """
6
- Create a list of accounts
7
- """
8
- accounts = []
9
- for _ in range(n_accounts):
10
- accounts.append(create_account())
11
- return accounts
8
+ return [create_account() for _ in range(n_accounts)]
12
9
 
13
10
 
14
- # Accounts for testing
15
- accounts = create_accounts(n_accounts=10)
11
+ def get_accounts() -> List[LocalAccount]:
12
+ general_config = get_general_config()
13
+ selected_network = general_config.get_network_name()
14
+ accounts = general_config.get_accounts_keys(selected_network)
15
+ return [create_account(account) for account in accounts]
16
16
 
17
- # Default account to use for transaction handling, if not specified
18
- default_account = accounts[0]
17
+
18
+ def get_default_account() -> LocalAccount:
19
+ general_config = get_general_config()
20
+ selected_network = general_config.get_network_name()
21
+ default_account_key = general_config.get_default_account_key(selected_network)
22
+ return create_account(default_account_key)
gltest/glchain/client.py CHANGED
@@ -1,8 +1,8 @@
1
1
  from genlayer_py.chains import localnet
2
2
  from genlayer_py import create_client
3
- from .account import default_account
3
+ from .account import get_default_account
4
4
  from functools import lru_cache
5
- from gltest.plugin_config import get_rpc_url
5
+ from gltest_cli.config.general import get_general_config
6
6
 
7
7
 
8
8
  @lru_cache(maxsize=1)
@@ -10,8 +10,44 @@ def get_gl_client():
10
10
  """
11
11
  Get the GenLayer client instance.
12
12
  """
13
+ general_config = get_general_config()
14
+ chain = general_config.get_chain()
15
+ default_account = get_default_account()
16
+ endpoint = general_config.get_rpc_url()
13
17
  return create_client(
14
- chain=localnet, account=default_account, endpoint=get_rpc_url()
18
+ chain=chain,
19
+ account=default_account,
20
+ endpoint=endpoint,
21
+ )
22
+
23
+
24
+ @lru_cache(maxsize=1)
25
+ def get_gl_hosted_studio_client():
26
+ """
27
+ Get the GenLayer hosted studio client instance.
28
+
29
+ Note: This is a temporary solution to get contract schema.
30
+ TODO: Remove this once we have a proper way to get contract schema from testnet.
31
+ """
32
+ return create_client(
33
+ chain=localnet,
34
+ account=get_default_account(),
35
+ endpoint="https://studio.genlayer.com/api",
36
+ )
37
+
38
+
39
+ @lru_cache(maxsize=1)
40
+ def get_local_client():
41
+ """
42
+ Get the GenLayer local client instance.
43
+
44
+ Note: This is a temporary solution to get contract schema.
45
+ TODO: Remove this once we have a proper way to get contract schema from testnet.
46
+ """
47
+ return create_client(
48
+ chain=localnet,
49
+ account=get_default_account(),
50
+ endpoint="http://127.0.0.1:4000/api",
15
51
  )
16
52
 
17
53
 
@@ -12,11 +12,12 @@ from gltest.artifacts import (
12
12
  )
13
13
  from gltest.assertions import tx_execution_failed
14
14
  from gltest.exceptions import DeploymentError
15
- from .client import get_gl_client
15
+ from .client import get_gl_client, get_gl_hosted_studio_client, get_local_client
16
16
  from gltest.types import CalldataEncodable, GenLayerTransaction, TransactionStatus
17
17
  from typing import List, Any, Type, Optional, Dict, Callable
18
18
  import types
19
- from gltest.plugin_config import get_default_wait_interval, get_default_wait_retries
19
+ from gltest_cli.config.general import get_general_config
20
+ from gltest_cli.logging import logger
20
21
 
21
22
 
22
23
  @dataclass
@@ -101,15 +102,16 @@ class Contract:
101
102
  wait_interval: Optional[int] = None,
102
103
  wait_retries: Optional[int] = None,
103
104
  wait_triggered_transactions: bool = True,
104
- wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
105
+ wait_triggered_transactions_status: TransactionStatus = TransactionStatus.FINALIZED,
105
106
  ) -> GenLayerTransaction:
106
107
  """
107
108
  Wrapper to the contract write method.
108
109
  """
110
+ general_config = get_general_config()
109
111
  if wait_interval is None:
110
- wait_interval = get_default_wait_interval()
112
+ wait_interval = general_config.get_default_wait_interval()
111
113
  if wait_retries is None:
112
- wait_retries = get_default_wait_retries()
114
+ wait_retries = general_config.get_default_wait_retries()
113
115
  client = get_gl_client()
114
116
  tx_hash = client.write_contract(
115
117
  address=self.address,
@@ -178,6 +180,31 @@ class ContractFactory:
178
180
  contract_code=contract_info.contract_code,
179
181
  )
180
182
 
183
+ def _get_schema_with_fallback(self):
184
+ """Attempts to get the contract schema using multiple clients in a fallback pattern.
185
+
186
+ This method tries to get the contract schema in the following order:
187
+ 1. Hosted studio client
188
+ 2. Local client
189
+ 3. Regular client
190
+
191
+ Returns:
192
+ Optional[Dict[str, Any]]: The contract schema if successful, None if all attempts fail.
193
+ """
194
+ clients = (
195
+ ("hosted studio", get_gl_hosted_studio_client()),
196
+ ("local", get_local_client()),
197
+ ("default", get_gl_client()),
198
+ )
199
+ for label, client in clients:
200
+ try:
201
+ return client.get_contract_schema_for_code(
202
+ contract_code=self.contract_code
203
+ )
204
+ except Exception as e:
205
+ logger.warning("Schema fetch via %s client failed: %s", label, e)
206
+ return None
207
+
181
208
  def build_contract(
182
209
  self,
183
210
  contract_address: Union[Address, ChecksumAddress],
@@ -186,16 +213,13 @@ class ContractFactory:
186
213
  """
187
214
  Build contract from address
188
215
  """
189
- client = get_gl_client()
190
- try:
191
- schema = client.get_contract_schema(address=contract_address)
192
- return Contract.new(
193
- address=contract_address, schema=schema, account=account
194
- )
195
- except Exception as e:
216
+ schema = self._get_schema_with_fallback()
217
+ if schema is None:
196
218
  raise ValueError(
197
- f"Failed to build contract {self.contract_name}: {str(e)}"
198
- ) from e
219
+ "Failed to get schema from all clients (hosted studio, local, and regular)"
220
+ )
221
+
222
+ return Contract.new(address=contract_address, schema=schema, account=account)
199
223
 
200
224
  def deploy(
201
225
  self,
@@ -210,10 +234,12 @@ class ContractFactory:
210
234
  """
211
235
  Deploy the contract
212
236
  """
237
+ general_config = get_general_config()
213
238
  if wait_interval is None:
214
- wait_interval = get_default_wait_interval()
239
+ wait_interval = general_config.get_default_wait_interval()
215
240
  if wait_retries is None:
216
- wait_retries = get_default_wait_retries()
241
+ wait_retries = general_config.get_default_wait_retries()
242
+
217
243
  client = get_gl_client()
218
244
  try:
219
245
  tx_hash = client.deploy_contract(
@@ -229,22 +255,27 @@ class ContractFactory:
229
255
  interval=wait_interval,
230
256
  retries=wait_retries,
231
257
  )
232
- if (
233
- not tx_receipt
234
- or "data" not in tx_receipt
235
- or "contract_address" not in tx_receipt["data"]
236
- ):
258
+ if tx_execution_failed(tx_receipt):
237
259
  raise ValueError(
238
- "Invalid transaction receipt: missing contract address"
260
+ f"Deployment transaction finalized with error: {tx_receipt}"
239
261
  )
240
262
 
241
- if tx_execution_failed(tx_receipt):
263
+ if (
264
+ "tx_data_decoded" in tx_receipt
265
+ and "contract_address" in tx_receipt["tx_data_decoded"]
266
+ ):
267
+ contract_address = tx_receipt["tx_data_decoded"]["contract_address"]
268
+ elif "data" in tx_receipt and "contract_address" in tx_receipt["data"]:
269
+ contract_address = tx_receipt["data"]["contract_address"]
270
+ else:
271
+ raise ValueError("Transaction receipt missing contract address")
272
+
273
+ schema = self._get_schema_with_fallback()
274
+ if schema is None:
242
275
  raise ValueError(
243
- f"Deployment transaction finalized with error: {tx_receipt}"
276
+ "Failed to get schema from all clients (hosted studio, local, and regular)"
244
277
  )
245
278
 
246
- contract_address = tx_receipt["data"]["contract_address"]
247
- schema = client.get_contract_schema(address=contract_address)
248
279
  return Contract.new(
249
280
  address=contract_address, schema=schema, account=account
250
281
  )
@@ -7,7 +7,7 @@ from gltest.exceptions import (
7
7
  InvalidSnapshotError,
8
8
  FixtureAnonymousFunctionError,
9
9
  )
10
- from gltest.plugin_config import get_rpc_url
10
+ from gltest_cli.config.general import get_general_config
11
11
 
12
12
  SUPPORTED_RPC_DOMAINS = ["localhost", "127.0.0.1"]
13
13
 
@@ -34,7 +34,8 @@ def load_fixture(fixture: Callable[[], T]) -> T:
34
34
  if fixture.__name__ == "<lambda>":
35
35
  raise FixtureAnonymousFunctionError("Fixtures must be named functions")
36
36
 
37
- rpc_url = get_rpc_url()
37
+ general_config = get_general_config()
38
+ rpc_url = general_config.get_rpc_url()
38
39
  domain = urlparse(rpc_url).netloc.split(":")[0] # Extract domain without port
39
40
  if domain not in SUPPORTED_RPC_DOMAINS:
40
41
  return fixture()
File without changes
@@ -0,0 +1,10 @@
1
+ from genlayer_py.chains.localnet import SIMULATOR_JSON_RPC_URL
2
+ from pathlib import Path
3
+
4
+
5
+ GLTEST_CONFIG_FILE = "gltest.config.yaml"
6
+ DEFAULT_NETWORK = "localnet"
7
+ DEFAULT_RPC_URL = SIMULATOR_JSON_RPC_URL
8
+ DEFAULT_ENVIRONMENT = ".env"
9
+ DEFAULT_CONTRACTS_DIR = Path("contracts")
10
+ DEFAULT_NETWORK_ID = 61999
@@ -0,0 +1,10 @@
1
+ from gltest_cli.config.types import GeneralConfig
2
+
3
+
4
+ _general_config = GeneralConfig()
5
+
6
+
7
+ def get_general_config() -> GeneralConfig:
8
+ global _general_config
9
+
10
+ return _general_config