genlayer-test 0.1.2__tar.gz → 0.2.0__tar.gz

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 (64) hide show
  1. {genlayer_test-0.1.2/genlayer_test.egg-info → genlayer_test-0.2.0}/PKG-INFO +48 -11
  2. genlayer_test-0.1.2/PKG-INFO → genlayer_test-0.2.0/README.md +44 -26
  3. genlayer_test-0.1.2/README.md → genlayer_test-0.2.0/genlayer_test.egg-info/PKG-INFO +63 -5
  4. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/genlayer_test.egg-info/SOURCES.txt +2 -0
  5. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/genlayer_test.egg-info/top_level.txt +1 -0
  6. genlayer_test-0.2.0/gltest/artifacts/__init__.py +6 -0
  7. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/artifacts/contract.py +88 -13
  8. genlayer_test-0.2.0/gltest/assertions.py +59 -0
  9. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/glchain/contract.py +41 -5
  10. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/pyproject.toml +4 -6
  11. genlayer_test-0.2.0/tests/artifact/contracts/duplicate_ic_contract_1.py +22 -0
  12. genlayer_test-0.2.0/tests/artifact/contracts/duplicate_ic_contract_2.py +22 -0
  13. genlayer_test-0.2.0/tests/artifact/test_contract_definition.py +347 -0
  14. genlayer_test-0.2.0/tests/assertions/test_assertions.py +344 -0
  15. genlayer_test-0.1.2/gltest/artifacts/__init__.py +0 -3
  16. genlayer_test-0.1.2/gltest/assertions.py +0 -18
  17. genlayer_test-0.1.2/tests/artifact/test_contract_definition.py +0 -92
  18. genlayer_test-0.1.2/tests/assertions/test_assertions.py +0 -31
  19. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/LICENSE +0 -0
  20. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/genlayer_test.egg-info/dependency_links.txt +0 -0
  21. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/genlayer_test.egg-info/entry_points.txt +0 -0
  22. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/genlayer_test.egg-info/requires.txt +0 -0
  23. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/__init__.py +0 -0
  24. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/exceptions.py +0 -0
  25. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/glchain/__init__.py +0 -0
  26. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/glchain/account.py +0 -0
  27. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/glchain/client.py +0 -0
  28. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/helpers/__init__.py +0 -0
  29. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/helpers/fixture_snapshot.py +0 -0
  30. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/helpers/take_snapshot.py +0 -0
  31. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/plugin_config.py +0 -0
  32. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/plugin_hooks.py +0 -0
  33. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest/types.py +0 -0
  34. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/gltest_cli/main.py +0 -0
  35. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/setup.cfg +0 -0
  36. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/artifact/contracts/not_ic_contract.py +0 -0
  37. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/football_prediction_market.py +0 -0
  38. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/intelligent_oracle.py +0 -0
  39. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/intelligent_oracle_factory.py +0 -0
  40. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/llm_erc20.py +0 -0
  41. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/log_indexer.py +0 -0
  42. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/multi_file_contract/__init__.py +0 -0
  43. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/multi_file_contract/other.py +0 -0
  44. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/multi_read_erc20.py +0 -0
  45. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/multi_tenant_storage.py +0 -0
  46. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/read_erc20.py +0 -0
  47. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/storage.py +0 -0
  48. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/user_storage.py +0 -0
  49. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/contracts/wizard_of_coin.py +0 -0
  50. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_football_prediction_market.py +0 -0
  51. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_intelligent_oracle_factory.py +0 -0
  52. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_llm_erc20.py +0 -0
  53. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_log_indexer.py +0 -0
  54. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_multi_file_contract.py +0 -0
  55. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_multi_file_contract_legacy.py +0 -0
  56. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_multi_read_erc20.py +0 -0
  57. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_multi_tenant_storage.py +0 -0
  58. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_read_erc20.py +0 -0
  59. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_storage.py +0 -0
  60. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_storage_legacy.py +0 -0
  61. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_user_storage.py +0 -0
  62. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/examples/tests/test_wizard_of_coin.py +0 -0
  63. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/plugin/conftest.py +0 -0
  64. {genlayer_test-0.1.2 → genlayer_test-0.2.0}/tests/plugin/test_plugin_hooks.py +0 -0
@@ -1,18 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genlayer-test
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: GenLayer Testing Suite
5
5
  Author: GenLayer
6
6
  License-Expression: MIT
7
7
  Classifier: Development Status :: 4 - Beta
8
8
  Classifier: Intended Audience :: Developers
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.8
11
- Classifier: Programming Language :: Python :: 3.9
12
- Classifier: Programming Language :: Python :: 3.10
13
- Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
14
12
  Classifier: Topic :: Software Development :: Testing
15
- Requires-Python: >=3.8
13
+ Requires-Python: >=3.12
16
14
  Description-Content-Type: text/markdown
17
15
  License-File: LICENSE
18
16
  Requires-Dist: pytest
@@ -162,7 +160,7 @@ Before diving into the examples, let's understand the basic project structure:
162
160
  ```
163
161
  genlayer-example/
164
162
  ├── contracts/ # Contract definitions
165
- │ └── storage.gpy # Example storage contract
163
+ │ └── storage.py # Example storage contract
166
164
  └── test/ # Test files
167
165
  └── test_contract.py # Contract test cases
168
166
  ```
@@ -279,6 +277,44 @@ def test_write_methods():
279
277
  assert contract.get_storage() == "new_value"
280
278
  ```
281
279
 
280
+ ### Assertions
281
+
282
+ The GenLayer Testing Suite provides powerful assertion functions to validate transaction results and their output:
283
+
284
+ #### Basic Transaction Assertions
285
+
286
+ ```python
287
+ from gltest.assertions import tx_execution_succeeded, tx_execution_failed
288
+
289
+ # Basic success/failure checks
290
+ assert tx_execution_succeeded(tx_receipt)
291
+ assert tx_execution_failed(tx_receipt) # Opposite of tx_execution_succeeded
292
+ ```
293
+
294
+ #### Advanced Output Matching
295
+
296
+ You can match specific patterns in the transaction's stdout and stderr output using regex patterns, similar to pytest's `match` parameter:
297
+
298
+ ```python
299
+ # Simple string matching
300
+ assert tx_execution_succeeded(tx_receipt, match_std_out="Process completed")
301
+ assert tx_execution_failed(tx_receipt, match_std_err="Warning: deprecated")
302
+
303
+ # Regex pattern matching
304
+ assert tx_execution_succeeded(tx_receipt, match_std_out=r".*code \d+")
305
+ assert tx_execution_failed(tx_receipt, match_std_err=r"Method.*failed")
306
+ ```
307
+
308
+ #### Assertion Function Parameters
309
+
310
+ Both `tx_execution_succeeded` and `tx_execution_failed` accept the following parameters:
311
+
312
+ - `result`: The transaction result object from contract method calls
313
+ - `match_std_out` (optional): String or regex pattern to match in stdout
314
+ - `match_std_err` (optional): String or regex pattern to match in stderr
315
+
316
+ **Network Compatibility**: The stdout/stderr matching feature (`match_std_out` and `match_std_err` parameters) is only available when running on **studionet** and **localnet**. These features are not supported on testnet.
317
+
282
318
  For more example contracts, check out the [contracts directory](tests/examples/contracts) which contains various sample contracts demonstrating different features and use cases.
283
319
 
284
320
  ## 📝 Best Practices
@@ -354,7 +390,7 @@ For more example contracts, check out the [contracts directory](tests/examples/c
354
390
  # Default structure
355
391
  your_project/
356
392
  ├── contracts/ # Default contracts directory
357
- │ └── my_contract.gpy # Your contract file
393
+ │ └── my_contract.py # Your contract file
358
394
  └── tests/
359
395
  └── test_contract.py # Your test file
360
396
 
@@ -366,7 +402,8 @@ For more example contracts, check out the [contracts directory](tests/examples/c
366
402
  - **Problem**: Contracts aren't being recognized or loaded properly.
367
403
  - **Solution**: Follow the correct naming and structure conventions:
368
404
  ```python
369
- # Correct file: contracts/my_contract.gpy
405
+ # Correct file: contracts/my_contract.py
406
+
370
407
  # Correct structure:
371
408
  from genlayer import *
372
409
 
@@ -374,7 +411,7 @@ For more example contracts, check out the [contracts directory](tests/examples/c
374
411
  # Contract code here
375
412
  pass
376
413
 
377
- # Incorrect file: contracts/my_contract.py # Wrong extension
414
+
378
415
  # Incorrect structure:
379
416
  class MyContract: # Missing gl.Contract inheritance
380
417
  pass
@@ -385,7 +422,7 @@ For more example contracts, check out the [contracts directory](tests/examples/c
385
422
  - **Solution**: Verify your environment:
386
423
  ```bash
387
424
  # Check Python version
388
- python --version # Should be >= 3.8
425
+ python --version # Should be >= 3.12
389
426
 
390
427
  # Check GenLayer Studio status
391
428
  docker ps # Should show GenLayer Studio running
@@ -1,24 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: genlayer-test
3
- Version: 0.1.2
4
- Summary: GenLayer Testing Suite
5
- Author: GenLayer
6
- License-Expression: MIT
7
- Classifier: Development Status :: 4 - Beta
8
- Classifier: Intended Audience :: Developers
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.8
11
- Classifier: Programming Language :: Python :: 3.9
12
- Classifier: Programming Language :: Python :: 3.10
13
- Classifier: Programming Language :: Python :: 3.11
14
- Classifier: Topic :: Software Development :: Testing
15
- Requires-Python: >=3.8
16
- Description-Content-Type: text/markdown
17
- License-File: LICENSE
18
- Requires-Dist: pytest
19
- Requires-Dist: genlayer-py==0.3.0
20
- Dynamic: license-file
21
-
22
1
  # GenLayer Testing Suite
23
2
 
24
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/license/mit/)
@@ -162,7 +141,7 @@ Before diving into the examples, let's understand the basic project structure:
162
141
  ```
163
142
  genlayer-example/
164
143
  ├── contracts/ # Contract definitions
165
- │ └── storage.gpy # Example storage contract
144
+ │ └── storage.py # Example storage contract
166
145
  └── test/ # Test files
167
146
  └── test_contract.py # Contract test cases
168
147
  ```
@@ -279,6 +258,44 @@ def test_write_methods():
279
258
  assert contract.get_storage() == "new_value"
280
259
  ```
281
260
 
261
+ ### Assertions
262
+
263
+ The GenLayer Testing Suite provides powerful assertion functions to validate transaction results and their output:
264
+
265
+ #### Basic Transaction Assertions
266
+
267
+ ```python
268
+ from gltest.assertions import tx_execution_succeeded, tx_execution_failed
269
+
270
+ # Basic success/failure checks
271
+ assert tx_execution_succeeded(tx_receipt)
272
+ assert tx_execution_failed(tx_receipt) # Opposite of tx_execution_succeeded
273
+ ```
274
+
275
+ #### Advanced Output Matching
276
+
277
+ You can match specific patterns in the transaction's stdout and stderr output using regex patterns, similar to pytest's `match` parameter:
278
+
279
+ ```python
280
+ # Simple string matching
281
+ assert tx_execution_succeeded(tx_receipt, match_std_out="Process completed")
282
+ assert tx_execution_failed(tx_receipt, match_std_err="Warning: deprecated")
283
+
284
+ # Regex pattern matching
285
+ assert tx_execution_succeeded(tx_receipt, match_std_out=r".*code \d+")
286
+ assert tx_execution_failed(tx_receipt, match_std_err=r"Method.*failed")
287
+ ```
288
+
289
+ #### Assertion Function Parameters
290
+
291
+ Both `tx_execution_succeeded` and `tx_execution_failed` accept the following parameters:
292
+
293
+ - `result`: The transaction result object from contract method calls
294
+ - `match_std_out` (optional): String or regex pattern to match in stdout
295
+ - `match_std_err` (optional): String or regex pattern to match in stderr
296
+
297
+ **Network Compatibility**: The stdout/stderr matching feature (`match_std_out` and `match_std_err` parameters) is only available when running on **studionet** and **localnet**. These features are not supported on testnet.
298
+
282
299
  For more example contracts, check out the [contracts directory](tests/examples/contracts) which contains various sample contracts demonstrating different features and use cases.
283
300
 
284
301
  ## 📝 Best Practices
@@ -354,7 +371,7 @@ For more example contracts, check out the [contracts directory](tests/examples/c
354
371
  # Default structure
355
372
  your_project/
356
373
  ├── contracts/ # Default contracts directory
357
- │ └── my_contract.gpy # Your contract file
374
+ │ └── my_contract.py # Your contract file
358
375
  └── tests/
359
376
  └── test_contract.py # Your test file
360
377
 
@@ -366,7 +383,8 @@ For more example contracts, check out the [contracts directory](tests/examples/c
366
383
  - **Problem**: Contracts aren't being recognized or loaded properly.
367
384
  - **Solution**: Follow the correct naming and structure conventions:
368
385
  ```python
369
- # Correct file: contracts/my_contract.gpy
386
+ # Correct file: contracts/my_contract.py
387
+
370
388
  # Correct structure:
371
389
  from genlayer import *
372
390
 
@@ -374,7 +392,7 @@ For more example contracts, check out the [contracts directory](tests/examples/c
374
392
  # Contract code here
375
393
  pass
376
394
 
377
- # Incorrect file: contracts/my_contract.py # Wrong extension
395
+
378
396
  # Incorrect structure:
379
397
  class MyContract: # Missing gl.Contract inheritance
380
398
  pass
@@ -385,7 +403,7 @@ For more example contracts, check out the [contracts directory](tests/examples/c
385
403
  - **Solution**: Verify your environment:
386
404
  ```bash
387
405
  # Check Python version
388
- python --version # Should be >= 3.8
406
+ python --version # Should be >= 3.12
389
407
 
390
408
  # Check GenLayer Studio status
391
409
  docker ps # Should show GenLayer Studio running
@@ -1,3 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: genlayer-test
3
+ Version: 0.2.0
4
+ Summary: GenLayer Testing Suite
5
+ Author: GenLayer
6
+ License-Expression: MIT
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Topic :: Software Development :: Testing
13
+ Requires-Python: >=3.12
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: pytest
17
+ Requires-Dist: genlayer-py==0.3.0
18
+ Dynamic: license-file
19
+
1
20
  # GenLayer Testing Suite
2
21
 
3
22
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/license/mit/)
@@ -141,7 +160,7 @@ Before diving into the examples, let's understand the basic project structure:
141
160
  ```
142
161
  genlayer-example/
143
162
  ├── contracts/ # Contract definitions
144
- │ └── storage.gpy # Example storage contract
163
+ │ └── storage.py # Example storage contract
145
164
  └── test/ # Test files
146
165
  └── test_contract.py # Contract test cases
147
166
  ```
@@ -258,6 +277,44 @@ def test_write_methods():
258
277
  assert contract.get_storage() == "new_value"
259
278
  ```
260
279
 
280
+ ### Assertions
281
+
282
+ The GenLayer Testing Suite provides powerful assertion functions to validate transaction results and their output:
283
+
284
+ #### Basic Transaction Assertions
285
+
286
+ ```python
287
+ from gltest.assertions import tx_execution_succeeded, tx_execution_failed
288
+
289
+ # Basic success/failure checks
290
+ assert tx_execution_succeeded(tx_receipt)
291
+ assert tx_execution_failed(tx_receipt) # Opposite of tx_execution_succeeded
292
+ ```
293
+
294
+ #### Advanced Output Matching
295
+
296
+ You can match specific patterns in the transaction's stdout and stderr output using regex patterns, similar to pytest's `match` parameter:
297
+
298
+ ```python
299
+ # Simple string matching
300
+ assert tx_execution_succeeded(tx_receipt, match_std_out="Process completed")
301
+ assert tx_execution_failed(tx_receipt, match_std_err="Warning: deprecated")
302
+
303
+ # Regex pattern matching
304
+ assert tx_execution_succeeded(tx_receipt, match_std_out=r".*code \d+")
305
+ assert tx_execution_failed(tx_receipt, match_std_err=r"Method.*failed")
306
+ ```
307
+
308
+ #### Assertion Function Parameters
309
+
310
+ Both `tx_execution_succeeded` and `tx_execution_failed` accept the following parameters:
311
+
312
+ - `result`: The transaction result object from contract method calls
313
+ - `match_std_out` (optional): String or regex pattern to match in stdout
314
+ - `match_std_err` (optional): String or regex pattern to match in stderr
315
+
316
+ **Network Compatibility**: The stdout/stderr matching feature (`match_std_out` and `match_std_err` parameters) is only available when running on **studionet** and **localnet**. These features are not supported on testnet.
317
+
261
318
  For more example contracts, check out the [contracts directory](tests/examples/contracts) which contains various sample contracts demonstrating different features and use cases.
262
319
 
263
320
  ## 📝 Best Practices
@@ -333,7 +390,7 @@ For more example contracts, check out the [contracts directory](tests/examples/c
333
390
  # Default structure
334
391
  your_project/
335
392
  ├── contracts/ # Default contracts directory
336
- │ └── my_contract.gpy # Your contract file
393
+ │ └── my_contract.py # Your contract file
337
394
  └── tests/
338
395
  └── test_contract.py # Your test file
339
396
 
@@ -345,7 +402,8 @@ For more example contracts, check out the [contracts directory](tests/examples/c
345
402
  - **Problem**: Contracts aren't being recognized or loaded properly.
346
403
  - **Solution**: Follow the correct naming and structure conventions:
347
404
  ```python
348
- # Correct file: contracts/my_contract.gpy
405
+ # Correct file: contracts/my_contract.py
406
+
349
407
  # Correct structure:
350
408
  from genlayer import *
351
409
 
@@ -353,7 +411,7 @@ For more example contracts, check out the [contracts directory](tests/examples/c
353
411
  # Contract code here
354
412
  pass
355
413
 
356
- # Incorrect file: contracts/my_contract.py # Wrong extension
414
+
357
415
  # Incorrect structure:
358
416
  class MyContract: # Missing gl.Contract inheritance
359
417
  pass
@@ -364,7 +422,7 @@ For more example contracts, check out the [contracts directory](tests/examples/c
364
422
  - **Solution**: Verify your environment:
365
423
  ```bash
366
424
  # Check Python version
367
- python --version # Should be >= 3.8
425
+ python --version # Should be >= 3.12
368
426
 
369
427
  # Check GenLayer Studio status
370
428
  docker ps # Should show GenLayer Studio running
@@ -24,6 +24,8 @@ gltest/helpers/fixture_snapshot.py
24
24
  gltest/helpers/take_snapshot.py
25
25
  gltest_cli/main.py
26
26
  tests/artifact/test_contract_definition.py
27
+ tests/artifact/contracts/duplicate_ic_contract_1.py
28
+ tests/artifact/contracts/duplicate_ic_contract_2.py
27
29
  tests/artifact/contracts/not_ic_contract.py
28
30
  tests/assertions/test_assertions.py
29
31
  tests/examples/contracts/football_prediction_market.py
@@ -1,4 +1,5 @@
1
1
  dist
2
2
  gltest
3
3
  gltest_cli
4
+ scripts
4
5
  tests
@@ -0,0 +1,6 @@
1
+ from .contract import (
2
+ find_contract_definition_from_name,
3
+ find_contract_definition_from_path,
4
+ )
5
+
6
+ __all__ = ["find_contract_definition_from_name", "find_contract_definition_from_path"]
@@ -10,7 +10,7 @@ from typing import Union
10
10
 
11
11
  @dataclass
12
12
  class ContractDefinition:
13
- """Class that represents a contract definition from a .gpy file."""
13
+ """Class that represents a contract definition from a contract file."""
14
14
 
15
15
  contract_name: str
16
16
  contract_code: Union[str, bytes]
@@ -20,6 +20,8 @@ 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
+
23
25
  for file_path in contracts_dir.rglob("*"):
24
26
  if not file_path.suffix in [".gpy", ".py"]:
25
27
  continue
@@ -40,10 +42,24 @@ def search_path_by_class_name(contracts_dir: Path, contract_name: str) -> Path:
40
42
  and base.value.id == "gl"
41
43
  and base.attr == "Contract"
42
44
  ):
43
- return file_path
45
+ matching_files.append(file_path)
46
+ break
47
+ break
44
48
  except Exception as e:
45
- raise ValueError(f"Error reading file {file_path}: {e}")
46
- raise FileNotFoundError(f"Contract {contract_name} not found at: {contracts_dir}")
49
+ raise ValueError(f"Error reading file {file_path}: {e}") from e
50
+
51
+ if len(matching_files) == 0:
52
+ raise FileNotFoundError(
53
+ f"Contract {contract_name} not found at: {contracts_dir}"
54
+ )
55
+ if len(matching_files) > 1:
56
+ file_paths_str = ", ".join(str(f) for f in matching_files)
57
+ raise ValueError(
58
+ f"Multiple contracts named '{contract_name}' found in contracts directory. "
59
+ f"Found in files: {file_paths_str}. Please ensure contract names are unique."
60
+ ) from None
61
+
62
+ return matching_files[0]
47
63
 
48
64
 
49
65
  def compute_contract_code(
@@ -71,14 +87,35 @@ def compute_contract_code(
71
87
  return buffer.getvalue()
72
88
 
73
89
 
74
- def find_contract_definition(contract_name: str) -> Optional[ContractDefinition]:
75
- """
76
- Search in the contracts directory for a contract definition.
77
- """
78
- contracts_dir = get_contracts_dir()
79
- if not contracts_dir.exists():
80
- raise FileNotFoundError(f"Contracts directory not found at: {contracts_dir}")
81
- main_file_path = search_path_by_class_name(contracts_dir, contract_name)
90
+ def _extract_contract_name_from_file(file_path: Path) -> str:
91
+ """Extract contract name from a file by parsing the AST."""
92
+ try:
93
+ with open(file_path, "r") as f:
94
+ content = f.read()
95
+ tree = ast.parse(content)
96
+
97
+ # Search for class definitions that inherit from gl.Contract
98
+ for node in ast.walk(tree):
99
+ if isinstance(node, ast.ClassDef):
100
+ for base in node.bases:
101
+ if (
102
+ isinstance(base, ast.Attribute)
103
+ and isinstance(base.value, ast.Name)
104
+ and base.value.id == "gl"
105
+ and base.attr == "Contract"
106
+ ):
107
+ return node.name
108
+ except Exception as e:
109
+ raise ValueError(f"Error parsing contract file {file_path}: {e}") from e
110
+
111
+ raise ValueError(f"No valid contract class found in {file_path}")
112
+
113
+
114
+ def _create_contract_definition(
115
+ main_file_path: Path, contract_name: str
116
+ ) -> ContractDefinition:
117
+ """Create a ContractDefinition from a main file path and contract name."""
118
+ # Determine if it's a multifile contract
82
119
  main_file_dir = main_file_path.parent
83
120
  runner_file_path = None
84
121
  if main_file_path.name in ["__init__.py", "__init__.gpy"]:
@@ -87,9 +124,47 @@ def find_contract_definition(contract_name: str) -> Optional[ContractDefinition]
87
124
  if not runner_file_path.exists():
88
125
  # No runner file, so it's a single file contract
89
126
  runner_file_path = None
127
+
128
+ # Compute contract code
129
+ contract_code = compute_contract_code(main_file_path, runner_file_path)
130
+
90
131
  return ContractDefinition(
91
132
  contract_name=contract_name,
92
- contract_code=compute_contract_code(main_file_path, runner_file_path),
133
+ contract_code=contract_code,
93
134
  main_file_path=main_file_path,
94
135
  runner_file_path=runner_file_path,
95
136
  )
137
+
138
+
139
+ def find_contract_definition_from_name(
140
+ contract_name: str,
141
+ ) -> Optional[ContractDefinition]:
142
+ """
143
+ Search in the contracts directory for a contract definition.
144
+ """
145
+ contracts_dir = get_contracts_dir()
146
+ if not contracts_dir.exists():
147
+ raise FileNotFoundError(f"Contracts directory not found at: {contracts_dir}")
148
+
149
+ main_file_path = search_path_by_class_name(contracts_dir, contract_name)
150
+ return _create_contract_definition(main_file_path, contract_name)
151
+
152
+
153
+ def find_contract_definition_from_path(
154
+ contract_file_path: Union[str, Path],
155
+ ) -> ContractDefinition:
156
+ """
157
+ Create a ContractDefinition from a given file path relative to the contracts directory.
158
+ """
159
+ contracts_dir = get_contracts_dir()
160
+ if not contracts_dir.exists():
161
+ raise FileNotFoundError(f"Contracts directory not found at: {contracts_dir}")
162
+
163
+ # Resolve the file path relative to contracts directory
164
+ main_file_path = contracts_dir / contract_file_path
165
+ if not main_file_path.exists():
166
+ raise FileNotFoundError(f"Contract file not found at: {main_file_path}")
167
+
168
+ contract_name = _extract_contract_name_from_file(main_file_path)
169
+
170
+ return _create_contract_definition(main_file_path, contract_name)
@@ -0,0 +1,59 @@
1
+ import re
2
+ from typing import Optional
3
+ from genlayer_py.types import GenLayerTransaction
4
+
5
+
6
+ def tx_execution_succeeded(
7
+ result: GenLayerTransaction,
8
+ match_std_out: Optional[str] = None,
9
+ match_std_err: Optional[str] = None,
10
+ ) -> bool:
11
+ if "consensus_data" not in result:
12
+ return False
13
+ if "leader_receipt" not in result["consensus_data"]:
14
+ return False
15
+ if len(result["consensus_data"]["leader_receipt"]) == 0:
16
+ return False
17
+
18
+ leader_receipt = result["consensus_data"]["leader_receipt"][0]
19
+
20
+ if "execution_result" not in leader_receipt:
21
+ return False
22
+
23
+ execution_result = leader_receipt["execution_result"]
24
+
25
+ if execution_result != "SUCCESS":
26
+ return False
27
+
28
+ if match_std_out is not None or match_std_err is not None:
29
+ if "genvm_result" not in leader_receipt:
30
+ return False
31
+
32
+ genvm_result = leader_receipt["genvm_result"]
33
+
34
+ if match_std_out is not None:
35
+ if "stdout" not in genvm_result:
36
+ return False
37
+ try:
38
+ if not re.search(match_std_out, genvm_result["stdout"]):
39
+ return False
40
+ except re.error:
41
+ return False
42
+
43
+ if match_std_err is not None:
44
+ if "stderr" not in genvm_result:
45
+ return False
46
+ try:
47
+ if not re.search(match_std_err, genvm_result["stderr"]):
48
+ return False
49
+ except re.error:
50
+ return False
51
+ return True
52
+
53
+
54
+ def tx_execution_failed(
55
+ result: GenLayerTransaction,
56
+ match_std_out: Optional[str] = None,
57
+ match_std_err: Optional[str] = None,
58
+ ) -> bool:
59
+ return not tx_execution_succeeded(result, match_std_out, match_std_err)
@@ -4,8 +4,12 @@ from eth_typing import (
4
4
  )
5
5
  from eth_account.signers.local import LocalAccount
6
6
  from typing import Union
7
+ from pathlib import Path
7
8
  from dataclasses import dataclass
8
- from gltest.artifacts import find_contract_definition
9
+ from gltest.artifacts import (
10
+ find_contract_definition_from_name,
11
+ find_contract_definition_from_path,
12
+ )
9
13
  from gltest.assertions import tx_execution_failed
10
14
  from gltest.exceptions import DeploymentError
11
15
  from .client import get_gl_client
@@ -146,13 +150,13 @@ class ContractFactory:
146
150
  contract_code: str
147
151
 
148
152
  @classmethod
149
- def from_artifact(
153
+ def from_name(
150
154
  cls: Type["ContractFactory"], contract_name: str
151
155
  ) -> "ContractFactory":
152
156
  """
153
157
  Create a ContractFactory instance given the contract name.
154
158
  """
155
- contract_info = find_contract_definition(contract_name)
159
+ contract_info = find_contract_definition_from_name(contract_name)
156
160
  if contract_info is None:
157
161
  raise ValueError(
158
162
  f"Contract {contract_name} not found in the contracts directory"
@@ -161,6 +165,19 @@ class ContractFactory:
161
165
  contract_name=contract_name, contract_code=contract_info.contract_code
162
166
  )
163
167
 
168
+ @classmethod
169
+ def from_file_path(
170
+ cls: Type["ContractFactory"], contract_file_path: Union[str, Path]
171
+ ) -> "ContractFactory":
172
+ """
173
+ Create a ContractFactory instance given the contract file path.
174
+ """
175
+ contract_info = find_contract_definition_from_path(contract_file_path)
176
+ return cls(
177
+ contract_name=contract_info.contract_name,
178
+ contract_code=contract_info.contract_code,
179
+ )
180
+
164
181
  def build_contract(
165
182
  self,
166
183
  contract_address: Union[Address, ChecksumAddress],
@@ -237,8 +254,27 @@ class ContractFactory:
237
254
  ) from e
238
255
 
239
256
 
240
- def get_contract_factory(contract_name: str) -> ContractFactory:
257
+ def get_contract_factory(
258
+ contract_name: Optional[str] = None,
259
+ contract_file_path: Optional[Union[str, Path]] = None,
260
+ ) -> ContractFactory:
241
261
  """
242
262
  Get a ContractFactory instance for a contract.
263
+
264
+ Args:
265
+ contract_name: Name of the contract to load from artifacts
266
+ contract_file_path: Path to the contract file to load directly
267
+
268
+ Note: Exactly one of contract_name or contract_file_path must be provided.
243
269
  """
244
- return ContractFactory.from_artifact(contract_name)
270
+ if contract_name is not None and contract_file_path is not None:
271
+ raise ValueError(
272
+ "Only one of contract_name or contract_file_path should be provided"
273
+ )
274
+
275
+ if contract_name is None and contract_file_path is None:
276
+ raise ValueError("Either contract_name or contract_file_path must be provided")
277
+
278
+ if contract_name is not None:
279
+ return ContractFactory.from_name(contract_name)
280
+ return ContractFactory.from_file_path(contract_file_path)
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "genlayer-test"
7
- version = "0.1.2"
7
+ version = "0.2.0"
8
8
  description = "GenLayer Testing Suite"
9
9
  authors = [
10
10
  { name = "GenLayer" }
11
11
  ]
12
12
  license = "MIT"
13
13
  readme = "README.md"
14
- requires-python = ">=3.8"
14
+ requires-python = ">=3.12"
15
15
  dependencies = [
16
16
  "pytest",
17
17
  "genlayer-py==0.3.0",
@@ -20,10 +20,8 @@ classifiers = [
20
20
  "Development Status :: 4 - Beta",
21
21
  "Intended Audience :: Developers",
22
22
  "Programming Language :: Python :: 3",
23
- "Programming Language :: Python :: 3.8",
24
- "Programming Language :: Python :: 3.9",
25
- "Programming Language :: Python :: 3.10",
26
- "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
27
25
  "Topic :: Software Development :: Testing",
28
26
  ]
29
27