genlayer-test 0.1.3__py3-none-any.whl → 0.3.0__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.
- {genlayer_test-0.1.3.dist-info → genlayer_test-0.3.0.dist-info}/METADATA +77 -10
- genlayer_test-0.3.0.dist-info/RECORD +65 -0
- {genlayer_test-0.1.3.dist-info → genlayer_test-0.3.0.dist-info}/entry_points.txt +1 -1
- gltest/__init__.py +4 -4
- gltest/artifacts/__init__.py +5 -2
- gltest/artifacts/contract.py +94 -14
- gltest/glchain/__init__.py +3 -3
- gltest/glchain/account.py +15 -11
- gltest/glchain/client.py +39 -3
- gltest/glchain/contract.py +98 -31
- gltest/helpers/fixture_snapshot.py +3 -2
- gltest_cli/config/__init__.py +0 -0
- gltest_cli/config/constants.py +10 -0
- gltest_cli/config/general.py +10 -0
- gltest_cli/config/plugin.py +102 -0
- gltest_cli/config/types.py +137 -0
- gltest_cli/config/user.py +222 -0
- gltest_cli/logging.py +51 -0
- tests/__init__.py +0 -0
- tests/examples/tests/test_llm_erc20.py +2 -2
- tests/examples/tests/test_multi_read_erc20.py +13 -3
- tests/examples/tests/test_multi_tenant_storage.py +12 -3
- tests/examples/tests/test_read_erc20.py +2 -2
- tests/examples/tests/test_storage.py +4 -2
- tests/examples/tests/test_user_storage.py +17 -3
- tests/gltest/__init__.py +0 -0
- tests/gltest/artifact/__init__.py +0 -0
- tests/gltest/artifact/contracts/duplicate_ic_contract_1.py +22 -0
- tests/gltest/artifact/contracts/duplicate_ic_contract_2.py +22 -0
- tests/{artifact → gltest/artifact}/test_contract_definition.py +29 -30
- tests/gltest_cli/__init__.py +0 -0
- tests/gltest_cli/config/test_plugin.py +127 -0
- tests/gltest_cli/config/test_user.py +351 -0
- genlayer_test-0.1.3.dist-info/RECORD +0 -53
- gltest/plugin_config.py +0 -42
- gltest/plugin_hooks.py +0 -51
- tests/plugin/test_plugin_hooks.py +0 -78
- {genlayer_test-0.1.3.dist-info → genlayer_test-0.3.0.dist-info}/WHEEL +0 -0
- {genlayer_test-0.1.3.dist-info → genlayer_test-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {genlayer_test-0.1.3.dist-info → genlayer_test-0.3.0.dist-info}/top_level.txt +0 -0
- /tests/{plugin/conftest.py → conftest.py} +0 -0
- /tests/{artifact → gltest/artifact}/contracts/not_ic_contract.py +0 -0
- /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.
|
3
|
+
Version: 0.3.0
|
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:
|
17
|
+
Requires-Dist: setuptools>=77.0
|
18
|
+
Requires-Dist: genlayer-py==0.5.0
|
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,
|
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 ==
|
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
|
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
|
-
|
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
|
-
|
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
|
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(
|
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.0.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.0.dist-info/METADATA,sha256=daKEgnpolSsdJRa4yvqPIiciVNKGKePFWT2H-o-fLiQ,17231
|
62
|
+
genlayer_test-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
63
|
+
genlayer_test-0.3.0.dist-info/entry_points.txt,sha256=RWPcSArBpz_G4BYioh5L8Q8hyClRbSgzLimjcWMp-BQ,94
|
64
|
+
genlayer_test-0.3.0.dist-info/top_level.txt,sha256=-qiGZxTRBytujzgVcKpxjvQ-WNeUDjXa59ceGMwMpko,24
|
65
|
+
genlayer_test-0.3.0.dist-info/RECORD,,
|
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
|
-
|
7
|
-
|
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
|
-
"
|
17
|
-
"
|
16
|
+
"get_accounts",
|
17
|
+
"get_default_account",
|
18
18
|
]
|
gltest/artifacts/__init__.py
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
-
from .contract import
|
1
|
+
from .contract import (
|
2
|
+
find_contract_definition_from_name,
|
3
|
+
find_contract_definition_from_path,
|
4
|
+
)
|
2
5
|
|
3
|
-
__all__ = ["
|
6
|
+
__all__ = ["find_contract_definition_from_name", "find_contract_definition_from_path"]
|
gltest/artifacts/contract.py
CHANGED
@@ -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
|
5
|
+
from gltest_cli.config.general import get_general_config
|
6
6
|
import io
|
7
7
|
import zipfile
|
8
8
|
from typing import Union
|
@@ -20,8 +20,13 @@ class ContractDefinition:
|
|
20
20
|
|
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
|
+
matching_files = []
|
24
|
+
exclude_dirs = {".venv", "venv", "env", "build", "dist", "__pycache__", ".git"}
|
25
|
+
|
23
26
|
for file_path in contracts_dir.rglob("*"):
|
24
|
-
if
|
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"]:
|
25
30
|
continue
|
26
31
|
try:
|
27
32
|
# Read the file content
|
@@ -40,10 +45,24 @@ def search_path_by_class_name(contracts_dir: Path, contract_name: str) -> Path:
|
|
40
45
|
and base.value.id == "gl"
|
41
46
|
and base.attr == "Contract"
|
42
47
|
):
|
43
|
-
|
48
|
+
matching_files.append(file_path)
|
49
|
+
break
|
50
|
+
break
|
44
51
|
except Exception as e:
|
45
|
-
raise ValueError(f"Error reading file {file_path}: {e}")
|
46
|
-
|
52
|
+
raise ValueError(f"Error reading file {file_path}: {e}") from e
|
53
|
+
|
54
|
+
if len(matching_files) == 0:
|
55
|
+
raise FileNotFoundError(
|
56
|
+
f"Contract {contract_name} not found at: {contracts_dir}"
|
57
|
+
)
|
58
|
+
if len(matching_files) > 1:
|
59
|
+
file_paths_str = ", ".join(str(f) for f in matching_files)
|
60
|
+
raise ValueError(
|
61
|
+
f"Multiple contracts named '{contract_name}' found in contracts directory. "
|
62
|
+
f"Found in files: {file_paths_str}. Please ensure contract names are unique."
|
63
|
+
) from None
|
64
|
+
|
65
|
+
return matching_files[0]
|
47
66
|
|
48
67
|
|
49
68
|
def compute_contract_code(
|
@@ -71,14 +90,35 @@ def compute_contract_code(
|
|
71
90
|
return buffer.getvalue()
|
72
91
|
|
73
92
|
|
74
|
-
def
|
75
|
-
"""
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
93
|
+
def _extract_contract_name_from_file(file_path: Path) -> str:
|
94
|
+
"""Extract contract name from a file by parsing the AST."""
|
95
|
+
try:
|
96
|
+
with open(file_path, "r") as f:
|
97
|
+
content = f.read()
|
98
|
+
tree = ast.parse(content)
|
99
|
+
|
100
|
+
# Search for class definitions that inherit from gl.Contract
|
101
|
+
for node in ast.walk(tree):
|
102
|
+
if isinstance(node, ast.ClassDef):
|
103
|
+
for base in node.bases:
|
104
|
+
if (
|
105
|
+
isinstance(base, ast.Attribute)
|
106
|
+
and isinstance(base.value, ast.Name)
|
107
|
+
and base.value.id == "gl"
|
108
|
+
and base.attr == "Contract"
|
109
|
+
):
|
110
|
+
return node.name
|
111
|
+
except Exception as e:
|
112
|
+
raise ValueError(f"Error parsing contract file {file_path}: {e}") from e
|
113
|
+
|
114
|
+
raise ValueError(f"No valid contract class found in {file_path}")
|
115
|
+
|
116
|
+
|
117
|
+
def _create_contract_definition(
|
118
|
+
main_file_path: Path, contract_name: str
|
119
|
+
) -> ContractDefinition:
|
120
|
+
"""Create a ContractDefinition from a main file path and contract name."""
|
121
|
+
# Determine if it's a multifile contract
|
82
122
|
main_file_dir = main_file_path.parent
|
83
123
|
runner_file_path = None
|
84
124
|
if main_file_path.name in ["__init__.py", "__init__.gpy"]:
|
@@ -87,9 +127,49 @@ def find_contract_definition(contract_name: str) -> Optional[ContractDefinition]
|
|
87
127
|
if not runner_file_path.exists():
|
88
128
|
# No runner file, so it's a single file contract
|
89
129
|
runner_file_path = None
|
130
|
+
|
131
|
+
# Compute contract code
|
132
|
+
contract_code = compute_contract_code(main_file_path, runner_file_path)
|
133
|
+
|
90
134
|
return ContractDefinition(
|
91
135
|
contract_name=contract_name,
|
92
|
-
contract_code=
|
136
|
+
contract_code=contract_code,
|
93
137
|
main_file_path=main_file_path,
|
94
138
|
runner_file_path=runner_file_path,
|
95
139
|
)
|
140
|
+
|
141
|
+
|
142
|
+
def find_contract_definition_from_name(
|
143
|
+
contract_name: str,
|
144
|
+
) -> Optional[ContractDefinition]:
|
145
|
+
"""
|
146
|
+
Search in the contracts directory for a contract definition.
|
147
|
+
"""
|
148
|
+
general_config = get_general_config()
|
149
|
+
contracts_dir = general_config.get_contracts_dir()
|
150
|
+
if not contracts_dir.exists():
|
151
|
+
raise FileNotFoundError(f"Contracts directory not found at: {contracts_dir}")
|
152
|
+
|
153
|
+
main_file_path = search_path_by_class_name(contracts_dir, contract_name)
|
154
|
+
return _create_contract_definition(main_file_path, contract_name)
|
155
|
+
|
156
|
+
|
157
|
+
def find_contract_definition_from_path(
|
158
|
+
contract_file_path: Union[str, Path],
|
159
|
+
) -> ContractDefinition:
|
160
|
+
"""
|
161
|
+
Create a ContractDefinition from a given file path relative to the contracts directory.
|
162
|
+
"""
|
163
|
+
general_config = get_general_config()
|
164
|
+
contracts_dir = general_config.get_contracts_dir()
|
165
|
+
if not contracts_dir.exists():
|
166
|
+
raise FileNotFoundError(f"Contracts directory not found at: {contracts_dir}")
|
167
|
+
|
168
|
+
# Resolve the file path relative to contracts directory
|
169
|
+
main_file_path = contracts_dir / contract_file_path
|
170
|
+
if not main_file_path.exists():
|
171
|
+
raise FileNotFoundError(f"Contract file not found at: {main_file_path}")
|
172
|
+
|
173
|
+
contract_name = _extract_contract_name_from_file(main_file_path)
|
174
|
+
|
175
|
+
return _create_contract_definition(main_file_path, contract_name)
|
gltest/glchain/__init__.py
CHANGED
@@ -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
|
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
|
-
|
15
|
-
|
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
|
-
|
18
|
-
|
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
|
3
|
+
from .account import get_default_account
|
4
4
|
from functools import lru_cache
|
5
|
-
from
|
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=
|
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
|
|