Skip to content

Commit 85dd58a

Browse files
feat: deferred app calls, modular test context, refined access to value generators, numerous fixes/improvements (#4)
* feat: work in progress on asset, application related state ops * test: adding extra tests * feat: extra tests and implementation wrappers around AppLocal * chore: wip * chore: update src/algopy_testing/op.py Co-authored-by: Daniel McGregor <daniel.mcgregor@makerx.com.au> * feat: adding acctparamsget; extra tests; pr comments * refactor: adding final bits around AcctParamsGet; unit tests and fixes * refactor: adding lookup by index to acct/app/asset get ops; tweaking ci * refactor: addressing pr comments * chore: fixing failing test * refactor: simplifying test_context validation * use specific enum types in box example with latest puya version * include box types in algopy_testing * fix inconsistent usage of field names on application fields use state total overrides when determining state totals reduce usage of `import algopy` in implementations * expose fields property on application to aid debugging * added section to CONTRIBUTING.md describing relationship between `algopy` and `algopy_testing` * remove lazy algopy imports from utils remove some unnecessary ignores add TODO * simplify abimethod and add TODO's * add TODO for state totals * add some tests (including currently failing ones) for app transactions * feat: add arc4factory * refactor: ensuring underlying _key is properly reflected on local/global states * refactor: change guards for setting keys to explicitly check for None * refactor: use implementation types in internal mappings * refactor: remove usages of `import algopy` from op.py, remove explicit imports from typing module add TODO's * test: use non-abstract contract base * allow empty box prefix * refactor * use immutable param defaults * fix: handle populating foreign arrays correctly for abi method calls * refactor: remove lazy import algopy * remove irrelevant comment * initialize accounts correctly * build: adding post install command into examples venv in hatch settings * refactor: refine arc4 factory; add corresponding tests * chore: adding the missing clear methods * chore: merging everything from docs branch except docs changes * chore: merge conflicts * refactor: simplify txn implementations provide default values for unspecified txn fields * docs: adding pep257 formatter; using reST docstrings style for context.py * test: adding tests for scratch slots * refactor: renaming set_txn_fields -> scoped_txn_fields * chore: adding `amount` field and open question under TODO; also adding adding get_box_map that reuses get_box but appends the bytes box_map prefix * chore: bumping ruff * refactor: adding context manager for lsig args setup (similar to algopy.Txn) also running latest ruff - some rules are updated * refactor: move helper classes into their own file * refactor: simplify itxn loader * refactor: isolate get_test_context to reduce circular imports * chore: using multiprocessing in refresh test artifacts script * refactor: adding tests for ITxn, ITxnCreate and GITxn, fixing related bugs * refactor: default_creator -> default_sender; setting creator as default_sender * chore: parsing name to op name in ITxn * chore: updating default extension for mypy to use ms-python * test: remove incorrect test and replace with TODO * chore: add TODO about subroutine support * add stricter type checks for primitives * track when contracts are in a "creating" state or not * todos * refactor: moving GITxn class to itxn.py * refactor: generate arc4 signatures from types added more robust system for tracking arc4 types removed unneeded functions on StaticArray * only support native tuples when handling generic aliases in arc4 tuples * refactor: 1/2 adding paged access to clear state program in txn fields * refactor: consolidating txn and itxn related context attributes/methods * minor refactors * support arc4 structs * refactor: simplify logic sig implementation, and remove mapping * refactor: fix itxn op behaviour with program pages, and other array like fields * refactor: simplify account properties * refactor: move crypto ops into their own module * refactor: move pure ops into their own module * refactor: move other misc ops * refactor: consolidating value generators; ledger and txn contexts; * refactor: add active group/txn properties change local/global state storage to store values against the app, not the contract instance add UInt64Backed type to simplify serialization to/from int/bytes * refactor: remove nested private modules, replace usages of get_test_context with lazy_context * refactor: move inner transactions onto transaction group * refactor: remove scoped_lsig_args * refactor: remove maybe_active_app_id * refactor: include bool in test for uint64 * refactor: ensure arc4 values always have fully parametrized types * refactor: use _paramatize_type * refactor: addressing TODOs refactor: removing txn from method names inside txn context manager prop chore: restoring initial pre-commit refactor: expanding scoped_execution chore: remove redundant fields chore: addressing minor todos and removing the ones already addressed * refactor: adding unit tests for global/local state with implicit keys * refactor: improving handling of initial value for implicit global/local state keys * test: extra test cases for accessing implicit/explicit keyed local/global state * refactor: wip adding txn_group_for method * chore: fix linting errors * feat: continue with txn_group_for and add a test * chore: remove scoped_txn_fields methods * add some additional TODO's for scoped_execution * remove TODO * expand gaid TODO * tweak op.exit implementation and add TODO * remove arc4 property from AlgopyTestContext * add more TODOs * refactor: addressing TODOs; adding marketplace contract example (devrel bootcamps) * test: fixing failing tests --------- Co-authored-by: Daniel McGregor <daniel.mcgregor@makerx.com.au>
1 parent dfa0a1b commit 85dd58a

File tree

157 files changed

+18092
-6737
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

157 files changed

+18092
-6737
lines changed

.github/workflows/cd.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757
cache: "pip"
5858

5959
- name: Start LocalNet
60-
run: hatch run cicd:localnet_start
60+
run: pipx install algokit && algokit localnet start
6161

6262
- name: Check pre-commits
6363
run: hatch run check

.github/workflows/ci.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ name: Check Python Code (algopy_testing)
33
on:
44
workflow_call:
55
pull_request:
6+
schedule:
7+
- cron: "0 8 * * 1" # Each monday 8 AM UTC
68

79
jobs:
810
check-python:
@@ -21,14 +23,17 @@ jobs:
2123
cache: "pip"
2224

2325
- name: Start LocalNet
24-
run: hatch run cicd:localnet_start
26+
run: pipx install algokit && algokit localnet start
2527

2628
- name: Check pre-commits
2729
run: hatch run check
2830

2931
- name: Check pre-commits (examples)
3032
run: hatch run examples:check
3133

34+
- name: Validate examples folder
35+
run: hatch run validate_examples
36+
3237
- name: Check wheels can be built
3338
run: hatch build
3439

.pre-commit-config.yaml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
repos:
22
- repo: local
33
hooks:
4-
- id: pre-commit
4+
- id: pre-commit (src & examples)
55
name: pre-commit
66
description: "Run pre-commit task via hatch"
77
entry: hatch run pre_commit
88
language: system
99
additional_dependencies: []
1010
minimum_pre_commit_version: "0"
11-
12-
- id: examples-pre-commit
13-
name: examples-pre-commit
14-
description: "Run examples venv pre-commit task via hatch"
15-
entry: hatch run examples:pre_commit
16-
language: system
17-
additional_dependencies: []
18-
minimum_pre_commit_version: "0"

.vscode/extensions.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"recommendations": [
3+
"ms-python.python",
4+
"charliermarsh.ruff",
5+
"ms-python.mypy-type-checker",
6+
"ms-python.black-formatter",
7+
"tamasfe.even-better-toml",
8+
"editorconfig.editorconfig"
9+
]
10+
}

.vscode/settings.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@
2828
"ruff.codeAction.fixViolation": {
2929
"enable": true
3030
},
31-
32-
"mypy.configFile": "pyproject.toml",
33-
// set to empty array to use config from project
34-
"mypy.targets": ["--cache-dir=/dev/null"],
35-
"mypy.runUsingActiveInterpreter": true,
36-
"cSpell.words": ["addw", "mulw"]
31+
"mypy-type-checker.importStrategy": "fromEnvironment",
32+
"mypy-type-checker.args": [
33+
"--enable-incomplete-feature=Unpack",
34+
"--config-file=pyproject.toml",
35+
"--strict",
36+
"--show-column-numbers"
37+
]
3738
}

CONTRIBUTING.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,59 @@ Examples folder uses a dedicated 'venv.examples' virtual environment managed by
4040
Project relies on [python-semantic-release](https://python-semantic-release.readthedocs.io/en/latest/) for release automation.
4141

4242
Releases are triggered by a `workflow_dispatch` event on the `main` branch with `prerelease` set to accordingly using the `.github/workflows/cd.yaml` file.
43+
44+
# Implementation vs Stubs
45+
46+
The canonical definition of the algopy API comes from the [`alogrand-python`](https://pypi.org/project/algorand-python/) package which consists only of typing information defined in the `algopy-stubs` module.
47+
In this library the testing implementation should follow the "shape" of the API defined in these stubs. In particular, types, methods and attributes should reflect what is described in the stubs.
48+
49+
However, implementation specific details can diverge from what is described in the stubs. For example methods marked as `@staticmethod` in the stubs do not need to be static methods in the implementation.
50+
Implementation types may provide more methods or properties than described in the stubs, the stubs are just the minimal set of what should be defined.
51+
52+
The `algopy_testing` module contains the implementation of the stubs and additional parts of the testing framework.
53+
The `algopy` module is used to alias the relevant `algopy_testing` implementations into the correct namespaces defined in the stubs.
54+
55+
Implementations within `algopy_testing` should use `algopy_testing` types as much as possible, except for typing annotations which should use the `algopy` equivalents instead. A rule of thumb to follow is
56+
withing the `algopy_testing` module, `import algopy` should only be used for type definitions e.g.
57+
58+
```python
59+
import typing
60+
61+
if typing.TYPE_CHECKING:
62+
import algopy
63+
64+
def do_something_with_bytes(a: algopy.Bytes) -> algopy.Bytes:
65+
...
66+
```
67+
68+
Instance checks should be done via the `algopy_testing` namespace, this will ensure any additional attributes on the implementation will be type checked correctly e.g.
69+
70+
```python
71+
import algopy_testing
72+
73+
74+
def do_something(value: object) -> None:
75+
if isinstance(value, algopy_testing.Bytes):
76+
raw_bytes: bytes = value.value
77+
...
78+
```
79+
80+
Occasionally this will require silencing Mypy warnings, within the scope of the implementation code this is considered acceptable.
81+
82+
```python
83+
import typing
84+
85+
import algopy_testing
86+
87+
if typing.TYPE_CHECKING:
88+
import algopy
89+
90+
def get_some_bytes() -> algopy.Bytes:
91+
value = algopy_testing.Bytes(b"42")
92+
# in the following statement, the return type warning is silenced as
93+
# algopy.Bytes is an alias of algopy_testing.Bytes
94+
return value # type: ignore[return-value]
95+
```
96+
97+
98+

docs/coverage.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@ See which `algorand-python` stubs are implemented by the `algorand-python-testin
1515
| Primitives (UInt64, BigUInt, Bytes, String) | Implemented |
1616
| urange | Implemented |
1717
| All crypto ops in op.\* namespace (to be expanded in detail) | Implemented |
18-
| Txn, GTxn, ITxn | Implemented |
1918
| arc4.\* namespace (to be expanded in detail) | Implemented |
2019
| uenumerate | Implemented |
21-
| op.ITxnCreate | Implemented |
2220
| StateTotals | Implemented |
21+
| Txn, GTxn, ITxn | Emulated |
2322
| Asset | Emulated |
2423
| Account | Emulated |
2524
| Application | Emulated |
@@ -34,10 +33,11 @@ See which `algorand-python` stubs are implemented by the `algorand-python-testin
3433
| log | Emulated |
3534
| itxn.\* namespace (inner transactions) | Emulated |
3635
| gtxn.\* namespace (group transactions) | Emulated |
36+
| op.ITxnCreate | Emulated |
3737
| ensure_budget | Mockable |
3838
| op.EllipticCurve | Mockable |
39-
| op.AssetParamsGet | Mockable |
40-
| op.AppParamsGet | Mockable |
41-
| op.AppLocal | Mockable |
42-
| op.AppGlobal | Mockable |
43-
| op.AcctParamsGet | Mockable |
39+
| op.AssetParamsGet | Emulated |
40+
| op.AppParamsGet | Emulated |
41+
| op.AppLocal | Emulated |
42+
| op.AppGlobal | Emulated |
43+
| op.AcctParamsGet | Emulated |

examples/README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Algorand Python Testing examples
2+
3+
This directory contains examples demonstrating how to use algorand-python-testing to test smart contracts written in Algorand Python.
4+
5+
## Overview
6+
7+
`algorand-python-testing` provides a powerful framework for unit testing Algorand smart contracts written in Algorand Python. It allows developers to emulate AVM behavior in a Python interpreter, making it easier to write and run tests for your Algorand applications.
8+
9+
## Key Features
10+
11+
1. **Test Environment Setup**: Use the `context` fixture to set up a test environment that emulates AVM behavior.
12+
2. **Arrange, Act, Assert Pattern**: Examples follow the 'arrange, act, assert' pattern for clear and structured tests.
13+
3. **Asset and Account Creation**: Easily create test assets and accounts using `context.any.asset` and `context.any.account`.
14+
4. **State Manipulation**: Test global and local state changes in your smart contracts.
15+
5. **ABI Method Testing**: Examples of how to test ABI methods in your smart contracts.
16+
17+
## Quickstart
18+
19+
To run the examples in a self-contained manner:
20+
21+
1. Install [hatch](https://hatch.pypa.io/latest/)
22+
2. From the root of the repo, run:
23+
24+
```bash
25+
hatch run examples:test examples/<example_directory>
26+
```
27+
28+
Replace `<example_directory>` with the specific example you want to run (e.g., `auction`, `abi`, etc.).
29+
30+
## Writing Tests
31+
32+
When writing tests for your Algorand smart contracts:
33+
34+
1. Use the `context` fixture to set up your test environment.
35+
2. Create test assets and accounts as needed using `context.any.asset` and `context.any.account`.
36+
3. Interact with your smart contract methods.
37+
4. Assert the expected outcomes, including state changes and transaction results.
38+
39+
For detailed examples, refer to the individual test files in each example directory.
40+
41+
## Contributing
42+
43+
If you have additional examples or improvements, feel free to contribute by submitting a pull request.
44+
45+
1. Follow the [contribution guidelines](https://github.com/algorandfoundation/algorand-python-testing/blob/main/CONTRIBUTING.md).
46+
2. Create a new folder under `examples/` with your contract/signature and test files.
47+
3. If you are contributing a smart contract example make sure to name the file `contract.py`. For logic signatures, name it `signature.py`.
48+
4. For test files use `test_contract.py` or `test_signature.py` respectively.
49+
5. Use the default PR template when opening a PR, and describe what sort of example are you adding as well as which feature of `algorand-python-testing` it demonstrates.
50+
51+
## Resources
52+
53+
- [Algorand Developer Documentation](https://developer.algorand.org/)
54+
- [algorand-python](https://algorandfoundation.github.io/puya/)
55+
- [algorand-python-testing](https://algorandfoundation.github.io/algorand-python-testing/)
56+
- ['arrange, act, assert' patern](https://automationpanda.com/2020/07/07/arrange-act-assert-a-pattern-for-writing-good-tests/)

0 commit comments

Comments
 (0)