Skip to content

Commit b714783

Browse files
authored
chore: extra exceptions for discouraging nested contexts (#20)
* chore: extra exceptions for discouraging nested contexts * chore: adjusting finally block to ensure active group is reset upon execution * docs: refining docs * ci: improving documentation hatch scripts * ci: adding doctest checks as part of main ci * docs: note on future refinement * docs: further refining the api section
1 parent 367dd54 commit b714783

File tree

11 files changed

+139
-32
lines changed

11 files changed

+139
-32
lines changed

.github/workflows/ci.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@ jobs:
4242

4343
- name: Run tests (examples)
4444
run: hatch run examples:tests
45+
46+
- name: Check doctests
47+
run: hatch run docs:test

.github/workflows/gh-pages.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ jobs:
2424
python-version: "3.12"
2525
cache: "pip"
2626

27+
- name: Test doctests
28+
run: hatch run docs:test
29+
2730
- name: Build doc
2831
run: hatch run docs:build
2932

docs/api.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# API Reference
22

3+
An overview of the `algorand-python-testing`'s `algopy_testing` module - covering the main classes and functions.
4+
5+
```{hint}
6+
Spotted a typo in documentation? This project is open source, please submit an issue or a PR on [GitHub](https://github.com/algorand/algorand-python-testing).
7+
```
8+
9+
```{warning}
10+
Note, assume `_algopy_testing` to refer to `algopy_testing` namespace in the auto-generated class documentation above. To be patched in near future.
11+
```
12+
313
## Contexts
414

515
```{autodoc2-summary}

docs/conf.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,13 @@
8484
sphinxmermaid_mermaid_init = {
8585
"theme": "dark",
8686
}
87+
88+
# Ignore specific warning types
89+
# TODO : remove upon refining autodoc2 (or finding alternative to sphinx)
90+
suppress_warnings = [
91+
"myst.xref_missing",
92+
"autodoc2.dup_item",
93+
"ref.python", # Ignore Python reference warnings
94+
"ref.class", # Ignore class reference warnings
95+
"ref.obj", # Ignore object reference warnings
96+
]

docs/faq.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# FAQ
2+
3+
## What is a Test Context?
4+
5+
A Test Context is a context manager that provides a simulated Algorand environment for testing Python smart contracts. It allows developers to create and manipulate a virtual Algorand ecosystem for testing purposes. For more details, see the [Test Context section](testing-guide/concepts.md#test-context) in our documentation.
6+
7+
## What is the Algorand Virtual Machine (AVM)?
8+
9+
The Algorand Virtual Machine (AVM) is the runtime environment for Algorand smart contracts. It executes the compiled code of smart contracts on the Algorand blockchain. To learn more about the AVM, visit the [official Algorand documentation](https://developer.algorand.org/docs/get-details/dapps/avm/).
10+
11+
## What are Operational Codes in Algorand?
12+
13+
Operational Codes, or opcodes, are AVM instructions that are executed directly by the AVM. In the context of Algorand Python testing, these opcodes are provided by `algopy` stubs and are either emulated, implemented, or mocked by `algorand-python-testing`. For a comprehensive list of opcodes, refer to the [Algorand Developer Documentation](https://developer.algorand.org/docs/get-details/dapps/avm/teal/opcodes/?from_query=OPcodes#template-modal-overlay).
14+
15+
## What are Value Generators?
16+
17+
Value Generators are helper methods that generate randomized values for testing when the specific value of the tested type is not important. In the context of Algorand Python testing, these are represented by property on the context manager, accessed via `any.*` (or `any.arc4.*`, `any.txn.*`. in the case of ARC 4 types). To understand how to use Value Generators effectively, check out our [Value Generators section](testing-guide/concepts.md#value-generators) in the documentation.
18+
19+
## What are the limitations of the Algorand Python Testing framework?
20+
21+
The Algorand Python Testing framework emulates the Algorand Virtual Machine (AVM) for unit testing Algorand Python smart contracts without interacting with the real Algorand Network. However, it has some limitations due to its scope and purpose:
22+
23+
1. Simplified balance tracking and transaction validation
24+
2. No consensus mechanism or AVM network operations simulation
25+
3. Absence of a strict opcode budget system
26+
4. Certain cryptographic operations are mocked or simplified
27+
5. No state proof generation or verification
28+
29+
For scenarios where these limitations are crucial, it's recommended to pair this framework with integration testing. If you have a solid reason to justify introducing new emulated behaviour, please open an issue or contribute to the project on [Github](https://github.com/algorandfoundation/algorand-python-testing).
30+
31+
## How does balance tracking work in the testing framework?
32+
33+
The framework uses simplified balance tracking and transaction validation. For scenarios where precise balance or fee verification is important, it's recommended to complement unit tests with integration testing.
34+
35+
## Does the framework simulate the entire AVM network?
36+
37+
No, the framework does not simulate the entire AVM network or consensus mechanism. It focuses on emulating the parts of the AVM relevant to unit testing smart contracts.
38+
39+
## How does the framework handle opcode budgets?
40+
41+
The framework does not implement a strict opcode budget system. For scenarios where validating opcode budget is crucial, it's recommended to use integration testing alongside this framework.
42+
43+
## Are all cryptographic operations fully implemented?
44+
45+
Some cryptographic operations are mocked or simplified in the framework. For a detailed list of which operations are mocked, refer to the _mockable_ types under the [coverage](./coverage.md) section.
46+
47+
## Can I use this framework for security-critical validations?
48+
49+
While this framework is useful for unit testing and local development, it should not be the only tool used for security-critical validations or performance benchmarking. It's designed to approximate AVM behavior for common scenarios. Always complement your testing with additional integration testing options available in `algokit`, where you can test against real localnet or testnet environments.
50+
51+
## Is there an example of how to use this framework alongside integration tests?
52+
53+
Yes, the `algokit-python-template`, accessible via `algokit init`, provides a working example of how to structure `algorand-python-testing` along with regular integration tests against localnet.
54+
55+
```{hint}
56+
An `algokit-python-template` accessible via `algokit init -t python`, provides a comprehensive and customizable working example of how to structure `algorand-python-testing` along with regular integration tests against localnet.
57+
```
58+
59+
## Is it compatible with `pytest`?
60+
61+
Yes, it is compatible with `pytest` and _any_ other python testing framework as its agnostic of the testing framework as long as its python. If you spot incompatibility with a certain tool, please open an issue or contribute to the project on [Github](https://github.com/algorandfoundation/algorand-python-testing).

docs/glossary.md

Lines changed: 0 additions & 8 deletions
This file was deleted.

docs/index.md

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,6 @@ The `algorand-python-testing` package provides:
1313
- An offline testing environment that simulates core AVM functionality
1414
- A familiar Pythonic experience, compatible with testing frameworks like [pytest](https://docs.pytest.org/en/latest/), [unittest](https://docs.python.org/3/library/unittest.html), and [hypothesis](https://hypothesis.readthedocs.io/en/latest/)
1515

16-
```{testsetup}
17-
import algopy
18-
import algopy_testing
19-
from algopy_testing import algopy_testing_context
20-
21-
# Create the context manager for snippets below
22-
ctx_manager = algopy_testing_context()
23-
24-
# Enter the context
25-
context = ctx_manager.__enter__()
26-
```
27-
2816
## Quick Start
2917

3018
`algopy` is a prerequisite for `algorand-python-testing`, providing stubs and type annotations for Algorand Python syntax. It enhances code completion and type checking when writing smart contracts. Note that this code isn't directly executable in standard Python interpreters; it's compiled by `puya` into TEAL for Algorand Network deployment.
@@ -188,11 +176,7 @@ hidden: true
188176
testing-guide/index
189177
examples
190178
coverage
191-
glossary
179+
faq
192180
api
193181
algopy
194182
```
195-
196-
```{testcleanup}
197-
ctx_manager.__exit__(None, None, None)
198-
```

pyproject.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,10 @@ post-install-commands = [
150150
]
151151

152152
[tool.hatch.envs.docs.scripts]
153-
build = "sphinx-build -b doctest docs docs/_build -W --keep-going -n -E"
154-
dev = "sphinx-build -b doctest docs docs/_build && sphinx-autobuild docs docs/_build"
153+
test = "sphinx-build -b doctest docs docs/_build -W --keep-going -n -E"
154+
clear = "rm -rf docs/_build"
155+
build = "hatch run docs:clear && sphinx-build docs docs/_build -W --keep-going -n -E"
156+
dev = "hatch run docs:test && sphinx-autobuild docs docs/_build"
155157

156158
# Examples environment
157159
[tool.hatch.envs.examples]

src/_algopy_testing/context_helpers/context_storage.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ def algopy_testing_context(
104104
"""
105105
from _algopy_testing.context import AlgopyTestContext
106106

107+
if _var.get(None) is not None:
108+
raise RuntimeError("Nested `algopy_testing_context`s are not allowed.")
109+
107110
token = _var.set(
108111
AlgopyTestContext(
109112
default_sender=default_sender,

src/_algopy_testing/context_helpers/txn_context.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ def create_group(
145145
:param active_txn_overrides: Overrides for active txn
146146
:return: None
147147
"""
148+
if self._active_group is not None:
149+
raise RuntimeError("Nested `create_group` calls are not allowed.")
148150
if gtxns and active_txn_overrides:
149151
raise ValueError("cannot specified gtxns and active_txn_overrides at the same time")
150152
if active_txn_index is not None and not gtxns:
@@ -164,18 +166,18 @@ def create_group(
164166
last_app_call_txn = app_calls[-1]._txns[-1]
165167
active_txn_index = processed_gtxns.index(last_app_call_txn)
166168

167-
previous_group = self._active_group
168-
active_group = self._active_group = TransactionGroup(
169+
new_group = TransactionGroup(
169170
txns=processed_gtxns,
170171
active_txn_index=active_txn_index,
171172
active_txn_overrides=typing.cast(dict[str, typing.Any], active_txn_overrides),
172173
)
174+
self._active_group = new_group
173175
try:
174176
yield
175177
finally:
176-
if active_group.txns:
177-
self._groups.append(active_group)
178-
self._active_group = previous_group
178+
if new_group.txns:
179+
self._groups.append(new_group)
180+
self._active_group = None
179181

180182
@contextlib.contextmanager
181183
def _get_or_create_group(self) -> Iterator[TransactionGroup]:

0 commit comments

Comments
 (0)