diff --git a/.github/workflows/check-python.yaml b/.github/workflows/check-python.yaml
index 4958c23..cbe0df5 100644
--- a/.github/workflows/check-python.yaml
+++ b/.github/workflows/check-python.yaml
@@ -16,10 +16,10 @@ jobs:
- name: Install algokit
run: pipx install algokit
- - name: Set up Python 3.10
+ - name: Set up Python 3.12
uses: actions/setup-python@v4
with:
- python-version: "3.10"
+ python-version: "3.12"
cache: "poetry"
- name: Install dependencies
diff --git a/README.md b/README.md
index 808c449..f2da27d 100644
--- a/README.md
+++ b/README.md
@@ -1,40 +1,42 @@
-

+
-
-
+
+
---
-This template provides a production-ready baseline for developing and deploying [Beaker](https://github.com/algorand-devrel/beaker) smart contracts.
+This template provides a production-ready baseline for developing and deploying [Puya](https://github.com/algorand-devrel/puya) smart contracts.
-To use it [install AlgoKit](https://github.com/algorandfoundation/algokit-cli#readme) and then either pass in `-t beaker_production` to `algokit init` or select the `beaker_production` template.
+To use it [install AlgoKit](https://github.com/algorandfoundation/algokit-cli#readme) and then either pass in `-t puya` to `algokit init` or select the `puya` template.
This is one of the official templates used by AlgoKit to initialize an Algorand smart contract project. It's a [Copier template](https://copier.readthedocs.io/en/stable/).
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
## Features
This template supports the following features:
-- Compilation of [multiple Beaker contracts](template_content/smart_contracts/config.py) to a [predictable folder location and file layout](template_content/smart_contracts/__main__.py) where they can be deployed
-- Deploy-time immutability and permanence control
-- [Poetry](https://python-poetry.org/) for Python dependency management and virtual environment management
-- Linting via [Ruff](https://github.com/charliermarsh/ruff) or [Flake8](https://flake8.pycqa.org/en/latest/)
-- Formatting via [Black](https://github.com/psf/black)
-- Type checking via [mypy](https://mypy-lang.org/)
-- Testing via pytest (not yet used)
-- Dependency vulnerability scanning via pip-audit (not yet used)
-- VS Code configuration (linting, formatting, breakpoint debugging)
-- dotenv (.env) file for configuration
-- Automated testing of the compiled smart contracts
-- [Output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) tests of the TEAL output
-- CI/CD pipeline using GitHub Actions:
-- - Optionally pick deployments to Netlify or Vercel
+- Compilation of [multiple Puya contracts](template_content/smart_contracts/config.py) to a [predictable folder location and file layout](template_content/smart_contracts/__main__.py) where they can be deployed
+- Deploy-time immutability and permanence control
+- [Poetry](https://python-poetry.org/) for Python dependency management and virtual environment management
+- Linting via [Ruff](https://github.com/charliermarsh/ruff) or [Flake8](https://flake8.pycqa.org/en/latest/)
+- Formatting via [Black](https://github.com/psf/black)
+- Type checking via [mypy](https://mypy-lang.org/)
+- Testing via pytest (not yet used)
+- Dependency vulnerability scanning via pip-audit (not yet used)
+- VS Code configuration (linting, formatting, breakpoint debugging)
+- dotenv (.env) file for configuration
+- Automated testing of the compiled smart contracts
+- [Output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) tests of the TEAL output
+- CI/CD pipeline using GitHub Actions:
+- - Optionally pick deployments to Netlify or Vercel
# Getting started
diff --git a/copier.yaml b/copier.yaml
index 2ccf085..962dc64 100644
--- a/copier.yaml
+++ b/copier.yaml
@@ -8,13 +8,13 @@ project_name:
help: Name for this project.
placeholder: "algorand-app"
-preset_name:
- type: str
- help: Name of the preset to use. Starter is optimal for simpler projects, Production is optimal for more complex projects that require CI/CD and other features.
- choices:
- Starter: "starter"
- Production: "production"
- default: "starter"
+# preset_name:
+# type: str
+# help: Name of the preset to use. Starter is optimal for simpler projects, Production is optimal for more complex projects that require CI/CD and other features.
+# choices:
+# Starter: "starter"
+# Production: "production"
+# default: "starter"
contract_name:
type: str
@@ -58,17 +58,12 @@ deployment_language:
python_linter:
type: str
help: Do you want to use a Python linter?
- when: "{{ preset_name == 'production' }}"
choices:
Ruff: "ruff"
Flake8: "flake8"
No thanks: "none"
default: |-
- {% if preset_name == 'production' -%}
- ruff
- {%- else -%}
- none
- {%- endif %}
+ ruff
use_python_black:
type: bool
@@ -77,14 +72,9 @@ use_python_black:
use_python_mypy:
type: bool
- when: "{{ preset_name == 'production' }}"
help: Do you want to use a Python type checker (via mypy)?
default: |-
- {% if preset_name == 'production' -%}
- yes
- {%- else -%}
- no
- {%- endif %}
+ yes
use_python_pytest:
type: bool
@@ -93,35 +83,23 @@ use_python_pytest:
use_python_pip_audit:
type: bool
- when: "{{ preset_name == 'production' }}"
help: Do you want to include Python dependency vulnerability scanning (via pip-audit)?
default: yes
use_github_actions:
type: bool
- when: "{{ preset_name == 'production' }}"
help: Do you want to include Github Actions workflows for build and testnet deployment?
default: |-
- {% if preset_name == 'production' -%}
- yes
- {%- else -%}
- no
- {%- endif %}
+ yes
use_pre_commit:
type: bool
- when: "{{ preset_name == 'production' }}"
help: Do you want to include pre-commit for linting, type checking and formatting?
default: |-
- {% if preset_name == 'production' -%}
- yes
- {%- else -%}
- no
- {%- endif %}
+ yes
use_dispenser:
type: bool
- when: "{{ preset_name == 'production' }}"
help: Do you want to fund your deployment account using an optional dispenser account?
default: no
diff --git a/poetry.lock b/poetry.lock
index 93ce6ef..2450613 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -2,111 +2,98 @@
[[package]]
name = "aiohttp"
-version = "3.8.4"
+version = "3.9.1"
description = "Async http client/server framework (asyncio)"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
files = [
- {file = "aiohttp-3.8.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5ce45967538fb747370308d3145aa68a074bdecb4f3a300869590f725ced69c1"},
- {file = "aiohttp-3.8.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b744c33b6f14ca26b7544e8d8aadff6b765a80ad6164fb1a430bbadd593dfb1a"},
- {file = "aiohttp-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a45865451439eb320784918617ba54b7a377e3501fb70402ab84d38c2cd891b"},
- {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a86d42d7cba1cec432d47ab13b6637bee393a10f664c425ea7b305d1301ca1a3"},
- {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee3c36df21b5714d49fc4580247947aa64bcbe2939d1b77b4c8dcb8f6c9faecc"},
- {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:176a64b24c0935869d5bbc4c96e82f89f643bcdf08ec947701b9dbb3c956b7dd"},
- {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c844fd628851c0bc309f3c801b3a3d58ce430b2ce5b359cd918a5a76d0b20cb5"},
- {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5393fb786a9e23e4799fec788e7e735de18052f83682ce2dfcabaf1c00c2c08e"},
- {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e4b09863aae0dc965c3ef36500d891a3ff495a2ea9ae9171e4519963c12ceefd"},
- {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:adfbc22e87365a6e564c804c58fc44ff7727deea782d175c33602737b7feadb6"},
- {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:147ae376f14b55f4f3c2b118b95be50a369b89b38a971e80a17c3fd623f280c9"},
- {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:eafb3e874816ebe2a92f5e155f17260034c8c341dad1df25672fb710627c6949"},
- {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6cc15d58053c76eacac5fa9152d7d84b8d67b3fde92709195cb984cfb3475ea"},
- {file = "aiohttp-3.8.4-cp310-cp310-win32.whl", hash = "sha256:59f029a5f6e2d679296db7bee982bb3d20c088e52a2977e3175faf31d6fb75d1"},
- {file = "aiohttp-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:fe7ba4a51f33ab275515f66b0a236bcde4fb5561498fe8f898d4e549b2e4509f"},
- {file = "aiohttp-3.8.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d8ef1a630519a26d6760bc695842579cb09e373c5f227a21b67dc3eb16cfea4"},
- {file = "aiohttp-3.8.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b3f2e06a512e94722886c0827bee9807c86a9f698fac6b3aee841fab49bbfb4"},
- {file = "aiohttp-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a80464982d41b1fbfe3154e440ba4904b71c1a53e9cd584098cd41efdb188ef"},
- {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b631e26df63e52f7cce0cce6507b7a7f1bc9b0c501fcde69742130b32e8782f"},
- {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f43255086fe25e36fd5ed8f2ee47477408a73ef00e804cb2b5cba4bf2ac7f5e"},
- {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d347a172f866cd1d93126d9b239fcbe682acb39b48ee0873c73c933dd23bd0f"},
- {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3fec6a4cb5551721cdd70473eb009d90935b4063acc5f40905d40ecfea23e05"},
- {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80a37fe8f7c1e6ce8f2d9c411676e4bc633a8462844e38f46156d07a7d401654"},
- {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d1e6a862b76f34395a985b3cd39a0d949ca80a70b6ebdea37d3ab39ceea6698a"},
- {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cd468460eefef601ece4428d3cf4562459157c0f6523db89365202c31b6daebb"},
- {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:618c901dd3aad4ace71dfa0f5e82e88b46ef57e3239fc7027773cb6d4ed53531"},
- {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:652b1bff4f15f6287550b4670546a2947f2a4575b6c6dff7760eafb22eacbf0b"},
- {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80575ba9377c5171407a06d0196b2310b679dc752d02a1fcaa2bc20b235dbf24"},
- {file = "aiohttp-3.8.4-cp311-cp311-win32.whl", hash = "sha256:bbcf1a76cf6f6dacf2c7f4d2ebd411438c275faa1dc0c68e46eb84eebd05dd7d"},
- {file = "aiohttp-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:6e74dd54f7239fcffe07913ff8b964e28b712f09846e20de78676ce2a3dc0bfc"},
- {file = "aiohttp-3.8.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:880e15bb6dad90549b43f796b391cfffd7af373f4646784795e20d92606b7a51"},
- {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb96fa6b56bb536c42d6a4a87dfca570ff8e52de2d63cabebfd6fb67049c34b6"},
- {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a6cadebe132e90cefa77e45f2d2f1a4b2ce5c6b1bfc1656c1ddafcfe4ba8131"},
- {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f352b62b45dff37b55ddd7b9c0c8672c4dd2eb9c0f9c11d395075a84e2c40f75"},
- {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ab43061a0c81198d88f39aaf90dae9a7744620978f7ef3e3708339b8ed2ef01"},
- {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9cb1565a7ad52e096a6988e2ee0397f72fe056dadf75d17fa6b5aebaea05622"},
- {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:1b3ea7edd2d24538959c1c1abf97c744d879d4e541d38305f9bd7d9b10c9ec41"},
- {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7c7837fe8037e96b6dd5cfcf47263c1620a9d332a87ec06a6ca4564e56bd0f36"},
- {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:3b90467ebc3d9fa5b0f9b6489dfb2c304a1db7b9946fa92aa76a831b9d587e99"},
- {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:cab9401de3ea52b4b4c6971db5fb5c999bd4260898af972bf23de1c6b5dd9d71"},
- {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d1f9282c5f2b5e241034a009779e7b2a1aa045f667ff521e7948ea9b56e0c5ff"},
- {file = "aiohttp-3.8.4-cp36-cp36m-win32.whl", hash = "sha256:5e14f25765a578a0a634d5f0cd1e2c3f53964553a00347998dfdf96b8137f777"},
- {file = "aiohttp-3.8.4-cp36-cp36m-win_amd64.whl", hash = "sha256:4c745b109057e7e5f1848c689ee4fb3a016c8d4d92da52b312f8a509f83aa05e"},
- {file = "aiohttp-3.8.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:aede4df4eeb926c8fa70de46c340a1bc2c6079e1c40ccf7b0eae1313ffd33519"},
- {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ddaae3f3d32fc2cb4c53fab020b69a05c8ab1f02e0e59665c6f7a0d3a5be54f"},
- {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4eb3b82ca349cf6fadcdc7abcc8b3a50ab74a62e9113ab7a8ebc268aad35bb9"},
- {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bcb89336efa095ea21b30f9e686763f2be4478f1b0a616969551982c4ee4c3b"},
- {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c08e8ed6fa3d477e501ec9db169bfac8140e830aa372d77e4a43084d8dd91ab"},
- {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6cd05ea06daca6ad6a4ca3ba7fe7dc5b5de063ff4daec6170ec0f9979f6c332"},
- {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7a00a9ed8d6e725b55ef98b1b35c88013245f35f68b1b12c5cd4100dddac333"},
- {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:de04b491d0e5007ee1b63a309956eaed959a49f5bb4e84b26c8f5d49de140fa9"},
- {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:40653609b3bf50611356e6b6554e3a331f6879fa7116f3959b20e3528783e699"},
- {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dbf3a08a06b3f433013c143ebd72c15cac33d2914b8ea4bea7ac2c23578815d6"},
- {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854f422ac44af92bfe172d8e73229c270dc09b96535e8a548f99c84f82dde241"},
- {file = "aiohttp-3.8.4-cp37-cp37m-win32.whl", hash = "sha256:aeb29c84bb53a84b1a81c6c09d24cf33bb8432cc5c39979021cc0f98c1292a1a"},
- {file = "aiohttp-3.8.4-cp37-cp37m-win_amd64.whl", hash = "sha256:db3fc6120bce9f446d13b1b834ea5b15341ca9ff3f335e4a951a6ead31105480"},
- {file = "aiohttp-3.8.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fabb87dd8850ef0f7fe2b366d44b77d7e6fa2ea87861ab3844da99291e81e60f"},
- {file = "aiohttp-3.8.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91f6d540163f90bbaef9387e65f18f73ffd7c79f5225ac3d3f61df7b0d01ad15"},
- {file = "aiohttp-3.8.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d265f09a75a79a788237d7f9054f929ced2e69eb0bb79de3798c468d8a90f945"},
- {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d89efa095ca7d442a6d0cbc755f9e08190ba40069b235c9886a8763b03785da"},
- {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4dac314662f4e2aa5009977b652d9b8db7121b46c38f2073bfeed9f4049732cd"},
- {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe11310ae1e4cd560035598c3f29d86cef39a83d244c7466f95c27ae04850f10"},
- {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ddb2a2026c3f6a68c3998a6c47ab6795e4127315d2e35a09997da21865757f8"},
- {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e75b89ac3bd27d2d043b234aa7b734c38ba1b0e43f07787130a0ecac1e12228a"},
- {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6e601588f2b502c93c30cd5a45bfc665faaf37bbe835b7cfd461753068232074"},
- {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a5d794d1ae64e7753e405ba58e08fcfa73e3fad93ef9b7e31112ef3c9a0efb52"},
- {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a1f4689c9a1462f3df0a1f7e797791cd6b124ddbee2b570d34e7f38ade0e2c71"},
- {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3032dcb1c35bc330134a5b8a5d4f68c1a87252dfc6e1262c65a7e30e62298275"},
- {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8189c56eb0ddbb95bfadb8f60ea1b22fcfa659396ea36f6adcc521213cd7b44d"},
- {file = "aiohttp-3.8.4-cp38-cp38-win32.whl", hash = "sha256:33587f26dcee66efb2fff3c177547bd0449ab7edf1b73a7f5dea1e38609a0c54"},
- {file = "aiohttp-3.8.4-cp38-cp38-win_amd64.whl", hash = "sha256:e595432ac259af2d4630008bf638873d69346372d38255774c0e286951e8b79f"},
- {file = "aiohttp-3.8.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5a7bdf9e57126dc345b683c3632e8ba317c31d2a41acd5800c10640387d193ed"},
- {file = "aiohttp-3.8.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:22f6eab15b6db242499a16de87939a342f5a950ad0abaf1532038e2ce7d31567"},
- {file = "aiohttp-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7235604476a76ef249bd64cb8274ed24ccf6995c4a8b51a237005ee7a57e8643"},
- {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea9eb976ffdd79d0e893869cfe179a8f60f152d42cb64622fca418cd9b18dc2a"},
- {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92c0cea74a2a81c4c76b62ea1cac163ecb20fb3ba3a75c909b9fa71b4ad493cf"},
- {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:493f5bc2f8307286b7799c6d899d388bbaa7dfa6c4caf4f97ef7521b9cb13719"},
- {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a63f03189a6fa7c900226e3ef5ba4d3bd047e18f445e69adbd65af433add5a2"},
- {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10c8cefcff98fd9168cdd86c4da8b84baaa90bf2da2269c6161984e6737bf23e"},
- {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bca5f24726e2919de94f047739d0a4fc01372801a3672708260546aa2601bf57"},
- {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:03baa76b730e4e15a45f81dfe29a8d910314143414e528737f8589ec60cf7391"},
- {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8c29c77cc57e40f84acef9bfb904373a4e89a4e8b74e71aa8075c021ec9078c2"},
- {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:03543dcf98a6619254b409be2d22b51f21ec66272be4ebda7b04e6412e4b2e14"},
- {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17b79c2963db82086229012cff93ea55196ed31f6493bb1ccd2c62f1724324e4"},
- {file = "aiohttp-3.8.4-cp39-cp39-win32.whl", hash = "sha256:34ce9f93a4a68d1272d26030655dd1b58ff727b3ed2a33d80ec433561b03d67a"},
- {file = "aiohttp-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:41a86a69bb63bb2fc3dc9ad5ea9f10f1c9c8e282b471931be0268ddd09430b04"},
- {file = "aiohttp-3.8.4.tar.gz", hash = "sha256:bf2e1a9162c1e441bf805a1fd166e249d574ca04e03b34f97e2928769e91ab5c"},
+ {file = "aiohttp-3.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1f80197f8b0b846a8d5cf7b7ec6084493950d0882cc5537fb7b96a69e3c8590"},
+ {file = "aiohttp-3.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72444d17777865734aa1a4d167794c34b63e5883abb90356a0364a28904e6c0"},
+ {file = "aiohttp-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9b05d5cbe9dafcdc733262c3a99ccf63d2f7ce02543620d2bd8db4d4f7a22f83"},
+ {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c4fa235d534b3547184831c624c0b7c1e262cd1de847d95085ec94c16fddcd5"},
+ {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:289ba9ae8e88d0ba16062ecf02dd730b34186ea3b1e7489046fc338bdc3361c4"},
+ {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bff7e2811814fa2271be95ab6e84c9436d027a0e59665de60edf44e529a42c1f"},
+ {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81b77f868814346662c96ab36b875d7814ebf82340d3284a31681085c051320f"},
+ {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b9c7426923bb7bd66d409da46c41e3fb40f5caf679da624439b9eba92043fa6"},
+ {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8d44e7bf06b0c0a70a20f9100af9fcfd7f6d9d3913e37754c12d424179b4e48f"},
+ {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22698f01ff5653fe66d16ffb7658f582a0ac084d7da1323e39fd9eab326a1f26"},
+ {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ca7ca5abfbfe8d39e653870fbe8d7710be7a857f8a8386fc9de1aae2e02ce7e4"},
+ {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8d7f98fde213f74561be1d6d3fa353656197f75d4edfbb3d94c9eb9b0fc47f5d"},
+ {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5216b6082c624b55cfe79af5d538e499cd5f5b976820eac31951fb4325974501"},
+ {file = "aiohttp-3.9.1-cp310-cp310-win32.whl", hash = "sha256:0e7ba7ff228c0d9a2cd66194e90f2bca6e0abca810b786901a569c0de082f489"},
+ {file = "aiohttp-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:c7e939f1ae428a86e4abbb9a7c4732bf4706048818dfd979e5e2839ce0159f23"},
+ {file = "aiohttp-3.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:df9cf74b9bc03d586fc53ba470828d7b77ce51b0582d1d0b5b2fb673c0baa32d"},
+ {file = "aiohttp-3.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ecca113f19d5e74048c001934045a2b9368d77b0b17691d905af18bd1c21275e"},
+ {file = "aiohttp-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8cef8710fb849d97c533f259103f09bac167a008d7131d7b2b0e3a33269185c0"},
+ {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bea94403a21eb94c93386d559bce297381609153e418a3ffc7d6bf772f59cc35"},
+ {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91c742ca59045dce7ba76cab6e223e41d2c70d79e82c284a96411f8645e2afff"},
+ {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c93b7c2e52061f0925c3382d5cb8980e40f91c989563d3d32ca280069fd6a87"},
+ {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee2527134f95e106cc1653e9ac78846f3a2ec1004cf20ef4e02038035a74544d"},
+ {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11ff168d752cb41e8492817e10fb4f85828f6a0142b9726a30c27c35a1835f01"},
+ {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b8c3a67eb87394386847d188996920f33b01b32155f0a94f36ca0e0c635bf3e3"},
+ {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c7b5d5d64e2a14e35a9240b33b89389e0035e6de8dbb7ffa50d10d8b65c57449"},
+ {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:69985d50a2b6f709412d944ffb2e97d0be154ea90600b7a921f95a87d6f108a2"},
+ {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c9110c06eaaac7e1f5562caf481f18ccf8f6fdf4c3323feab28a93d34cc646bd"},
+ {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737e69d193dac7296365a6dcb73bbbf53bb760ab25a3727716bbd42022e8d7a"},
+ {file = "aiohttp-3.9.1-cp311-cp311-win32.whl", hash = "sha256:4ee8caa925aebc1e64e98432d78ea8de67b2272252b0a931d2ac3bd876ad5544"},
+ {file = "aiohttp-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:a34086c5cc285be878622e0a6ab897a986a6e8bf5b67ecb377015f06ed316587"},
+ {file = "aiohttp-3.9.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f800164276eec54e0af5c99feb9494c295118fc10a11b997bbb1348ba1a52065"},
+ {file = "aiohttp-3.9.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:500f1c59906cd142d452074f3811614be04819a38ae2b3239a48b82649c08821"},
+ {file = "aiohttp-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0b0a6a36ed7e164c6df1e18ee47afbd1990ce47cb428739d6c99aaabfaf1b3af"},
+ {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69da0f3ed3496808e8cbc5123a866c41c12c15baaaead96d256477edf168eb57"},
+ {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:176df045597e674fa950bf5ae536be85699e04cea68fa3a616cf75e413737eb5"},
+ {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b796b44111f0cab6bbf66214186e44734b5baab949cb5fb56154142a92989aeb"},
+ {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f27fdaadce22f2ef950fc10dcdf8048407c3b42b73779e48a4e76b3c35bca26c"},
+ {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcb6532b9814ea7c5a6a3299747c49de30e84472fa72821b07f5a9818bce0f66"},
+ {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:54631fb69a6e44b2ba522f7c22a6fb2667a02fd97d636048478db2fd8c4e98fe"},
+ {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4b4c452d0190c5a820d3f5c0f3cd8a28ace48c54053e24da9d6041bf81113183"},
+ {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:cae4c0c2ca800c793cae07ef3d40794625471040a87e1ba392039639ad61ab5b"},
+ {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:565760d6812b8d78d416c3c7cfdf5362fbe0d0d25b82fed75d0d29e18d7fc30f"},
+ {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54311eb54f3a0c45efb9ed0d0a8f43d1bc6060d773f6973efd90037a51cd0a3f"},
+ {file = "aiohttp-3.9.1-cp312-cp312-win32.whl", hash = "sha256:85c3e3c9cb1d480e0b9a64c658cd66b3cfb8e721636ab8b0e746e2d79a7a9eed"},
+ {file = "aiohttp-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:11cb254e397a82efb1805d12561e80124928e04e9c4483587ce7390b3866d213"},
+ {file = "aiohttp-3.9.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8a22a34bc594d9d24621091d1b91511001a7eea91d6652ea495ce06e27381f70"},
+ {file = "aiohttp-3.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:598db66eaf2e04aa0c8900a63b0101fdc5e6b8a7ddd805c56d86efb54eb66672"},
+ {file = "aiohttp-3.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c9376e2b09895c8ca8b95362283365eb5c03bdc8428ade80a864160605715f1"},
+ {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41473de252e1797c2d2293804e389a6d6986ef37cbb4a25208de537ae32141dd"},
+ {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c5857612c9813796960c00767645cb5da815af16dafb32d70c72a8390bbf690"},
+ {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffcd828e37dc219a72c9012ec44ad2e7e3066bec6ff3aaa19e7d435dbf4032ca"},
+ {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:219a16763dc0294842188ac8a12262b5671817042b35d45e44fd0a697d8c8361"},
+ {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f694dc8a6a3112059258a725a4ebe9acac5fe62f11c77ac4dcf896edfa78ca28"},
+ {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bcc0ea8d5b74a41b621ad4a13d96c36079c81628ccc0b30cfb1603e3dfa3a014"},
+ {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:90ec72d231169b4b8d6085be13023ece8fa9b1bb495e4398d847e25218e0f431"},
+ {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:cf2a0ac0615842b849f40c4d7f304986a242f1e68286dbf3bd7a835e4f83acfd"},
+ {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:0e49b08eafa4f5707ecfb321ab9592717a319e37938e301d462f79b4e860c32a"},
+ {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2c59e0076ea31c08553e868cec02d22191c086f00b44610f8ab7363a11a5d9d8"},
+ {file = "aiohttp-3.9.1-cp38-cp38-win32.whl", hash = "sha256:4831df72b053b1eed31eb00a2e1aff6896fb4485301d4ccb208cac264b648db4"},
+ {file = "aiohttp-3.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:3135713c5562731ee18f58d3ad1bf41e1d8883eb68b363f2ffde5b2ea4b84cc7"},
+ {file = "aiohttp-3.9.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cfeadf42840c1e870dc2042a232a8748e75a36b52d78968cda6736de55582766"},
+ {file = "aiohttp-3.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:70907533db712f7aa791effb38efa96f044ce3d4e850e2d7691abd759f4f0ae0"},
+ {file = "aiohttp-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cdefe289681507187e375a5064c7599f52c40343a8701761c802c1853a504558"},
+ {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7481f581251bb5558ba9f635db70908819caa221fc79ee52a7f58392778c636"},
+ {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49f0c1b3c2842556e5de35f122fc0f0b721334ceb6e78c3719693364d4af8499"},
+ {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d406b01a9f5a7e232d1b0d161b40c05275ffbcbd772dc18c1d5a570961a1ca4"},
+ {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d8e4450e7fe24d86e86b23cc209e0023177b6d59502e33807b732d2deb6975f"},
+ {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c0266cd6f005e99f3f51e583012de2778e65af6b73860038b968a0a8888487a"},
+ {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab221850108a4a063c5b8a70f00dd7a1975e5a1713f87f4ab26a46e5feac5a0e"},
+ {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c88a15f272a0ad3d7773cf3a37cc7b7d077cbfc8e331675cf1346e849d97a4e5"},
+ {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:237533179d9747080bcaad4d02083ce295c0d2eab3e9e8ce103411a4312991a0"},
+ {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:02ab6006ec3c3463b528374c4cdce86434e7b89ad355e7bf29e2f16b46c7dd6f"},
+ {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04fa38875e53eb7e354ece1607b1d2fdee2d175ea4e4d745f6ec9f751fe20c7c"},
+ {file = "aiohttp-3.9.1-cp39-cp39-win32.whl", hash = "sha256:82eefaf1a996060602f3cc1112d93ba8b201dbf5d8fd9611227de2003dddb3b7"},
+ {file = "aiohttp-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:9b05d33ff8e6b269e30a7957bd3244ffbce2a7a35a81b81c382629b80af1a8bf"},
+ {file = "aiohttp-3.9.1.tar.gz", hash = "sha256:8fc49a87ac269d4529da45871e2ffb6874e87779c3d0e2ccd813c0899221239d"},
]
[package.dependencies]
aiosignal = ">=1.1.2"
-async-timeout = ">=4.0.0a3,<5.0"
attrs = ">=17.3.0"
-charset-normalizer = ">=2.0,<4.0"
frozenlist = ">=1.1.1"
multidict = ">=4.5,<7.0"
yarl = ">=1.0,<2.0"
[package.extras]
-speedups = ["Brotli", "aiodns", "cchardet"]
+speedups = ["Brotli", "aiodns", "brotlicffi"]
[[package]]
name = "aiosignal"
@@ -124,27 +111,17 @@ frozenlist = ">=1.1.0"
[[package]]
name = "algokit-utils"
-version = "1.3.0"
+version = "1.4.0"
description = "Utilities for Algorand development for use by AlgoKit"
optional = false
python-versions = ">=3.10,<4.0"
files = [
- {file = "algokit_utils-1.3.0-py3-none-any.whl", hash = "sha256:7167daa4412b74fe23ec4000193f32f1553e149786e8db7f0a8ca9f47ba37536"},
+ {file = "algokit_utils-1.4.0-py3-none-any.whl", hash = "sha256:b6cc1dcc57047bbb2abfa05516306c51f2981f1a64f90e311d8a1bd5566c73a0"},
]
[package.dependencies]
-py-algorand-sdk = ">=2.2.0,<3.0.0"
-
-[[package]]
-name = "async-timeout"
-version = "4.0.2"
-description = "Timeout context manager for asyncio programs"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
- {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
-]
+deprecated = ">=1.2.14,<2.0.0"
+py-algorand-sdk = ">=2.4.0,<3.0.0"
[[package]]
name = "attrs"
@@ -164,21 +141,6 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-
tests = ["attrs[tests-no-zope]", "zope-interface"]
tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-[[package]]
-name = "beaker-pyteal"
-version = "1.0.1"
-description = "A Framework for building PyTeal Applications"
-optional = false
-python-versions = ">=3.10,<4.0"
-files = [
- {file = "beaker_pyteal-1.0.1-py3-none-any.whl", hash = "sha256:e10122de9761cf033ea2de557ef381f4cd4a83c80e3c38aeca32bac250da4c9c"},
-]
-
-[package.dependencies]
-algokit-utils = ">=1.0.2,<2.0.0"
-py-algorand-sdk = ">=2.0.0"
-pyteal = ">=0.24,<0.25"
-
[[package]]
name = "black"
version = "22.12.0"
@@ -206,7 +168,6 @@ click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0"
platformdirs = ">=2"
-tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
[package.extras]
colorama = ["colorama (>=0.4.3)"]
@@ -216,75 +177,63 @@ uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "cffi"
-version = "1.15.1"
+version = "1.16.0"
description = "Foreign Function Interface for Python calling C code."
optional = false
-python-versions = "*"
+python-versions = ">=3.8"
files = [
- {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
- {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
- {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
- {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
- {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
- {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
- {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
- {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
- {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
- {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
- {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
- {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
- {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
- {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
- {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
- {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
- {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
- {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
- {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
- {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
- {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
- {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
- {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
- {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
- {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
- {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
- {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
- {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
- {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
- {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
- {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
- {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
- {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
- {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
- {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
- {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
- {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
- {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
- {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
- {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
- {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
- {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
- {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
- {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
- {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
- {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
- {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
- {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
- {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
- {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
- {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
- {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
- {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
- {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
- {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
- {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
- {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
- {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
- {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
- {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
- {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
- {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
- {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
- {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
+ {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"},
+ {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"},
+ {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"},
+ {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"},
+ {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"},
+ {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"},
+ {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"},
+ {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"},
+ {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"},
+ {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"},
+ {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"},
+ {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"},
+ {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"},
+ {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"},
+ {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"},
+ {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"},
+ {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"},
+ {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"},
+ {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"},
+ {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"},
+ {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"},
+ {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"},
+ {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"},
+ {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"},
+ {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"},
+ {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"},
+ {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"},
+ {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"},
+ {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"},
+ {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"},
+ {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"},
+ {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"},
+ {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"},
+ {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"},
+ {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"},
+ {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"},
+ {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"},
+ {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"},
+ {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"},
+ {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"},
+ {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"},
+ {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"},
+ {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"},
+ {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"},
+ {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"},
+ {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"},
+ {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"},
+ {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"},
+ {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"},
+ {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"},
+ {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"},
+ {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"},
]
[package.dependencies]
@@ -292,108 +241,24 @@ pycparser = "*"
[[package]]
name = "cfgv"
-version = "3.3.1"
+version = "3.4.0"
description = "Validate configuration and produce human readable error messages."
optional = false
-python-versions = ">=3.6.1"
-files = [
- {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
- {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
-]
-
-[[package]]
-name = "charset-normalizer"
-version = "3.1.0"
-description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-optional = false
-python-versions = ">=3.7.0"
+python-versions = ">=3.8"
files = [
- {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"},
- {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"},
- {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"},
- {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"},
- {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"},
- {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"},
- {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"},
+ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
+ {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
]
[[package]]
name = "click"
-version = "8.1.3"
+version = "8.1.7"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
files = [
- {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
- {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
+ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
+ {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
]
[package.dependencies]
@@ -411,41 +276,33 @@ files = [
]
[[package]]
-name = "distlib"
-version = "0.3.6"
-description = "Distribution utilities"
+name = "deprecated"
+version = "1.2.14"
+description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
optional = false
-python-versions = "*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
- {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"},
- {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"},
+ {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"},
+ {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"},
]
-[[package]]
-name = "docstring-parser"
-version = "0.14.1"
-description = "Parse Python docstrings in reST, Google and Numpydoc format"
-optional = false
-python-versions = ">=3.6,<4.0"
-files = [
- {file = "docstring_parser-0.14.1-py3-none-any.whl", hash = "sha256:14ac6ec1f1ba6905c4d8cb90fd0bc55394f5678183752c90e44812bf28d7a515"},
- {file = "docstring_parser-0.14.1.tar.gz", hash = "sha256:2c77522e31b7c88b1ab457a1f3c9ae38947ad719732260ba77ee8a3deb58622a"},
-]
+[package.dependencies]
+wrapt = ">=1.10,<2"
+
+[package.extras]
+dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"]
[[package]]
-name = "exceptiongroup"
-version = "1.1.1"
-description = "Backport of PEP 654 (exception groups)"
+name = "distlib"
+version = "0.3.8"
+description = "Distribution utilities"
optional = false
-python-versions = ">=3.7"
+python-versions = "*"
files = [
- {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"},
- {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"},
+ {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
+ {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
]
-[package.extras]
-test = ["pytest (>=6)"]
-
[[package]]
name = "execnet"
version = "2.0.2"
@@ -460,143 +317,117 @@ files = [
[package.extras]
testing = ["hatch", "pre-commit", "pytest", "tox"]
-[[package]]
-name = "executing"
-version = "1.2.0"
-description = "Get the currently executing AST node of a frame, and other information"
-optional = false
-python-versions = "*"
-files = [
- {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"},
- {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"},
-]
-
-[package.extras]
-tests = ["asttokens", "littleutils", "pytest", "rich"]
-
[[package]]
name = "filelock"
-version = "3.12.2"
+version = "3.13.1"
description = "A platform independent file lock."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"},
- {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"},
+ {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"},
+ {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"},
]
[package.extras]
-docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
-testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"]
+docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
+typing = ["typing-extensions (>=4.8)"]
[[package]]
name = "flake8"
-version = "6.0.0"
+version = "6.1.0"
description = "the modular source code checker: pep8 pyflakes and co"
optional = false
python-versions = ">=3.8.1"
files = [
- {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"},
- {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"},
+ {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"},
+ {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"},
]
[package.dependencies]
mccabe = ">=0.7.0,<0.8.0"
-pycodestyle = ">=2.10.0,<2.11.0"
-pyflakes = ">=3.0.0,<3.1.0"
+pycodestyle = ">=2.11.0,<2.12.0"
+pyflakes = ">=3.1.0,<3.2.0"
[[package]]
name = "frozenlist"
-version = "1.3.3"
+version = "1.4.0"
description = "A list-like structure which implements collections.abc.MutableSequence"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4"},
- {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dfbac4c2dfcc082fcf8d942d1e49b6aa0766c19d3358bd86e2000bf0fa4a9cf0"},
- {file = "frozenlist-1.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b1c63e8d377d039ac769cd0926558bb7068a1f7abb0f003e3717ee003ad85530"},
- {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fdfc24dcfce5b48109867c13b4cb15e4660e7bd7661741a391f821f23dfdca7"},
- {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c926450857408e42f0bbc295e84395722ce74bae69a3b2aa2a65fe22cb14b99"},
- {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1841e200fdafc3d51f974d9d377c079a0694a8f06de2e67b48150328d66d5483"},
- {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f470c92737afa7d4c3aacc001e335062d582053d4dbe73cda126f2d7031068dd"},
- {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:783263a4eaad7c49983fe4b2e7b53fa9770c136c270d2d4bbb6d2192bf4d9caf"},
- {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:924620eef691990dfb56dc4709f280f40baee568c794b5c1885800c3ecc69816"},
- {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae4dc05c465a08a866b7a1baf360747078b362e6a6dbeb0c57f234db0ef88ae0"},
- {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bed331fe18f58d844d39ceb398b77d6ac0b010d571cba8267c2e7165806b00ce"},
- {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:02c9ac843e3390826a265e331105efeab489ffaf4dd86384595ee8ce6d35ae7f"},
- {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9545a33965d0d377b0bc823dcabf26980e77f1b6a7caa368a365a9497fb09420"},
- {file = "frozenlist-1.3.3-cp310-cp310-win32.whl", hash = "sha256:d5cd3ab21acbdb414bb6c31958d7b06b85eeb40f66463c264a9b343a4e238642"},
- {file = "frozenlist-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:b756072364347cb6aa5b60f9bc18e94b2f79632de3b0190253ad770c5df17db1"},
- {file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4395e2f8d83fbe0c627b2b696acce67868793d7d9750e90e39592b3626691b7"},
- {file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14143ae966a6229350021384870458e4777d1eae4c28d1a7aa47f24d030e6678"},
- {file = "frozenlist-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5d8860749e813a6f65bad8285a0520607c9500caa23fea6ee407e63debcdbef6"},
- {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23d16d9f477bb55b6154654e0e74557040575d9d19fe78a161bd33d7d76808e8"},
- {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb82dbba47a8318e75f679690190c10a5e1f447fbf9df41cbc4c3afd726d88cb"},
- {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9309869032abb23d196cb4e4db574232abe8b8be1339026f489eeb34a4acfd91"},
- {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a97b4fe50b5890d36300820abd305694cb865ddb7885049587a5678215782a6b"},
- {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c188512b43542b1e91cadc3c6c915a82a5eb95929134faf7fd109f14f9892ce4"},
- {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:303e04d422e9b911a09ad499b0368dc551e8c3cd15293c99160c7f1f07b59a48"},
- {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0771aed7f596c7d73444c847a1c16288937ef988dc04fb9f7be4b2aa91db609d"},
- {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:66080ec69883597e4d026f2f71a231a1ee9887835902dbe6b6467d5a89216cf6"},
- {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:41fe21dc74ad3a779c3d73a2786bdf622ea81234bdd4faf90b8b03cad0c2c0b4"},
- {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f20380df709d91525e4bee04746ba612a4df0972c1b8f8e1e8af997e678c7b81"},
- {file = "frozenlist-1.3.3-cp311-cp311-win32.whl", hash = "sha256:f30f1928162e189091cf4d9da2eac617bfe78ef907a761614ff577ef4edfb3c8"},
- {file = "frozenlist-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a6394d7dadd3cfe3f4b3b186e54d5d8504d44f2d58dcc89d693698e8b7132b32"},
- {file = "frozenlist-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8df3de3a9ab8325f94f646609a66cbeeede263910c5c0de0101079ad541af332"},
- {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0693c609e9742c66ba4870bcee1ad5ff35462d5ffec18710b4ac89337ff16e27"},
- {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd4210baef299717db0a600d7a3cac81d46ef0e007f88c9335db79f8979c0d3d"},
- {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:394c9c242113bfb4b9aa36e2b80a05ffa163a30691c7b5a29eba82e937895d5e"},
- {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6327eb8e419f7d9c38f333cde41b9ae348bec26d840927332f17e887a8dcb70d"},
- {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e24900aa13212e75e5b366cb9065e78bbf3893d4baab6052d1aca10d46d944c"},
- {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3843f84a6c465a36559161e6c59dce2f2ac10943040c2fd021cfb70d58c4ad56"},
- {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:84610c1502b2461255b4c9b7d5e9c48052601a8957cd0aea6ec7a7a1e1fb9420"},
- {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:c21b9aa40e08e4f63a2f92ff3748e6b6c84d717d033c7b3438dd3123ee18f70e"},
- {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:efce6ae830831ab6a22b9b4091d411698145cb9b8fc869e1397ccf4b4b6455cb"},
- {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:40de71985e9042ca00b7953c4f41eabc3dc514a2d1ff534027f091bc74416401"},
- {file = "frozenlist-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:180c00c66bde6146a860cbb81b54ee0df350d2daf13ca85b275123bbf85de18a"},
- {file = "frozenlist-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9bbbcedd75acdfecf2159663b87f1bb5cfc80e7cd99f7ddd9d66eb98b14a8411"},
- {file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:034a5c08d36649591be1cbb10e09da9f531034acfe29275fc5454a3b101ce41a"},
- {file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba64dc2b3b7b158c6660d49cdb1d872d1d0bf4e42043ad8d5006099479a194e5"},
- {file = "frozenlist-1.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:47df36a9fe24054b950bbc2db630d508cca3aa27ed0566c0baf661225e52c18e"},
- {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:008a054b75d77c995ea26629ab3a0c0d7281341f2fa7e1e85fa6153ae29ae99c"},
- {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:841ea19b43d438a80b4de62ac6ab21cfe6827bb8a9dc62b896acc88eaf9cecba"},
- {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e235688f42b36be2b6b06fc37ac2126a73b75fb8d6bc66dd632aa35286238703"},
- {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca713d4af15bae6e5d79b15c10c8522859a9a89d3b361a50b817c98c2fb402a2"},
- {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ac5995f2b408017b0be26d4a1d7c61bce106ff3d9e3324374d66b5964325448"},
- {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4ae8135b11652b08a8baf07631d3ebfe65a4c87909dbef5fa0cdde440444ee4"},
- {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4ea42116ceb6bb16dbb7d526e242cb6747b08b7710d9782aa3d6732bd8d27649"},
- {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:810860bb4bdce7557bc0febb84bbd88198b9dbc2022d8eebe5b3590b2ad6c842"},
- {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ee78feb9d293c323b59a6f2dd441b63339a30edf35abcb51187d2fc26e696d13"},
- {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0af2e7c87d35b38732e810befb9d797a99279cbb85374d42ea61c1e9d23094b3"},
- {file = "frozenlist-1.3.3-cp38-cp38-win32.whl", hash = "sha256:899c5e1928eec13fd6f6d8dc51be23f0d09c5281e40d9cf4273d188d9feeaf9b"},
- {file = "frozenlist-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:7f44e24fa70f6fbc74aeec3e971f60a14dde85da364aa87f15d1be94ae75aeef"},
- {file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2b07ae0c1edaa0a36339ec6cce700f51b14a3fc6545fdd32930d2c83917332cf"},
- {file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ebb86518203e12e96af765ee89034a1dbb0c3c65052d1b0c19bbbd6af8a145e1"},
- {file = "frozenlist-1.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5cf820485f1b4c91e0417ea0afd41ce5cf5965011b3c22c400f6d144296ccbc0"},
- {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c11e43016b9024240212d2a65043b70ed8dfd3b52678a1271972702d990ac6d"},
- {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fa3c6e3305aa1146b59a09b32b2e04074945ffcfb2f0931836d103a2c38f936"},
- {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:352bd4c8c72d508778cf05ab491f6ef36149f4d0cb3c56b1b4302852255d05d5"},
- {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65a5e4d3aa679610ac6e3569e865425b23b372277f89b5ef06cf2cdaf1ebf22b"},
- {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e2c1185858d7e10ff045c496bbf90ae752c28b365fef2c09cf0fa309291669"},
- {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f163d2fd041c630fed01bc48d28c3ed4a3b003c00acd396900e11ee5316b56bb"},
- {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:05cdb16d09a0832eedf770cb7bd1fe57d8cf4eaf5aced29c4e41e3f20b30a784"},
- {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8bae29d60768bfa8fb92244b74502b18fae55a80eac13c88eb0b496d4268fd2d"},
- {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:eedab4c310c0299961ac285591acd53dc6723a1ebd90a57207c71f6e0c2153ab"},
- {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3bbdf44855ed8f0fbcd102ef05ec3012d6a4fd7c7562403f76ce6a52aeffb2b1"},
- {file = "frozenlist-1.3.3-cp39-cp39-win32.whl", hash = "sha256:efa568b885bca461f7c7b9e032655c0c143d305bf01c30caf6db2854a4532b38"},
- {file = "frozenlist-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9"},
- {file = "frozenlist-1.3.3.tar.gz", hash = "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"},
+ {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:764226ceef3125e53ea2cb275000e309c0aa5464d43bd72abd661e27fffc26ab"},
+ {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d6484756b12f40003c6128bfcc3fa9f0d49a687e171186c2d85ec82e3758c559"},
+ {file = "frozenlist-1.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9ac08e601308e41eb533f232dbf6b7e4cea762f9f84f6357136eed926c15d12c"},
+ {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d081f13b095d74b67d550de04df1c756831f3b83dc9881c38985834387487f1b"},
+ {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71932b597f9895f011f47f17d6428252fc728ba2ae6024e13c3398a087c2cdea"},
+ {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:981b9ab5a0a3178ff413bca62526bb784249421c24ad7381e39d67981be2c326"},
+ {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e41f3de4df3e80de75845d3e743b3f1c4c8613c3997a912dbf0229fc61a8b963"},
+ {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6918d49b1f90821e93069682c06ffde41829c346c66b721e65a5c62b4bab0300"},
+ {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e5c8764c7829343d919cc2dfc587a8db01c4f70a4ebbc49abde5d4b158b007b"},
+ {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8d0edd6b1c7fb94922bf569c9b092ee187a83f03fb1a63076e7774b60f9481a8"},
+ {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e29cda763f752553fa14c68fb2195150bfab22b352572cb36c43c47bedba70eb"},
+ {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:0c7c1b47859ee2cac3846fde1c1dc0f15da6cec5a0e5c72d101e0f83dcb67ff9"},
+ {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:901289d524fdd571be1c7be054f48b1f88ce8dddcbdf1ec698b27d4b8b9e5d62"},
+ {file = "frozenlist-1.4.0-cp310-cp310-win32.whl", hash = "sha256:1a0848b52815006ea6596c395f87449f693dc419061cc21e970f139d466dc0a0"},
+ {file = "frozenlist-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:b206646d176a007466358aa21d85cd8600a415c67c9bd15403336c331a10d956"},
+ {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de343e75f40e972bae1ef6090267f8260c1446a1695e77096db6cfa25e759a95"},
+ {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad2a9eb6d9839ae241701d0918f54c51365a51407fd80f6b8289e2dfca977cc3"},
+ {file = "frozenlist-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd7bd3b3830247580de99c99ea2a01416dfc3c34471ca1298bccabf86d0ff4dc"},
+ {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdf1847068c362f16b353163391210269e4f0569a3c166bc6a9f74ccbfc7e839"},
+ {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38461d02d66de17455072c9ba981d35f1d2a73024bee7790ac2f9e361ef1cd0c"},
+ {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5a32087d720c608f42caed0ef36d2b3ea61a9d09ee59a5142d6070da9041b8f"},
+ {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd65632acaf0d47608190a71bfe46b209719bf2beb59507db08ccdbe712f969b"},
+ {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261b9f5d17cac914531331ff1b1d452125bf5daa05faf73b71d935485b0c510b"},
+ {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b89ac9768b82205936771f8d2eb3ce88503b1556324c9f903e7156669f521472"},
+ {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01"},
+ {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e74b0506fa5aa5598ac6a975a12aa8928cbb58e1f5ac8360792ef15de1aa848f"},
+ {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:490132667476f6781b4c9458298b0c1cddf237488abd228b0b3650e5ecba7467"},
+ {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:76d4711f6f6d08551a7e9ef28c722f4a50dd0fc204c56b4bcd95c6cc05ce6fbb"},
+ {file = "frozenlist-1.4.0-cp311-cp311-win32.whl", hash = "sha256:a02eb8ab2b8f200179b5f62b59757685ae9987996ae549ccf30f983f40602431"},
+ {file = "frozenlist-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:515e1abc578dd3b275d6a5114030b1330ba044ffba03f94091842852f806f1c1"},
+ {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f0ed05f5079c708fe74bf9027e95125334b6978bf07fd5ab923e9e55e5fbb9d3"},
+ {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca265542ca427bf97aed183c1676e2a9c66942e822b14dc6e5f42e038f92a503"},
+ {file = "frozenlist-1.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:491e014f5c43656da08958808588cc6c016847b4360e327a62cb308c791bd2d9"},
+ {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17ae5cd0f333f94f2e03aaf140bb762c64783935cc764ff9c82dff626089bebf"},
+ {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e78fb68cf9c1a6aa4a9a12e960a5c9dfbdb89b3695197aa7064705662515de2"},
+ {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5655a942f5f5d2c9ed93d72148226d75369b4f6952680211972a33e59b1dfdc"},
+ {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c11b0746f5d946fecf750428a95f3e9ebe792c1ee3b1e96eeba145dc631a9672"},
+ {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e66d2a64d44d50d2543405fb183a21f76b3b5fd16f130f5c99187c3fb4e64919"},
+ {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:88f7bc0fcca81f985f78dd0fa68d2c75abf8272b1f5c323ea4a01a4d7a614efc"},
+ {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5833593c25ac59ede40ed4de6d67eb42928cca97f26feea219f21d0ed0959b79"},
+ {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e"},
+ {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:b826d97e4276750beca7c8f0f1a4938892697a6bcd8ec8217b3312dad6982781"},
+ {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ceb6ec0a10c65540421e20ebd29083c50e6d1143278746a4ef6bcf6153171eb8"},
+ {file = "frozenlist-1.4.0-cp38-cp38-win32.whl", hash = "sha256:2b8bcf994563466db019fab287ff390fffbfdb4f905fc77bc1c1d604b1c689cc"},
+ {file = "frozenlist-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:a6c8097e01886188e5be3e6b14e94ab365f384736aa1fca6a0b9e35bd4a30bc7"},
+ {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6c38721585f285203e4b4132a352eb3daa19121a035f3182e08e437cface44bf"},
+ {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a0c6da9aee33ff0b1a451e867da0c1f47408112b3391dd43133838339e410963"},
+ {file = "frozenlist-1.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93ea75c050c5bb3d98016b4ba2497851eadf0ac154d88a67d7a6816206f6fa7f"},
+ {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1"},
+ {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa384489fefeb62321b238e64c07ef48398fe80f9e1e6afeff22e140e0850eef"},
+ {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10ff5faaa22786315ef57097a279b833ecab1a0bfb07d604c9cbb1c4cdc2ed87"},
+ {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:007df07a6e3eb3e33e9a1fe6a9db7af152bbd8a185f9aaa6ece10a3529e3e1c6"},
+ {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4f399d28478d1f604c2ff9119907af9726aed73680e5ed1ca634d377abb087"},
+ {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5374b80521d3d3f2ec5572e05adc94601985cc526fb276d0c8574a6d749f1b3"},
+ {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ce31ae3e19f3c902de379cf1323d90c649425b86de7bbdf82871b8a2a0615f3d"},
+ {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7211ef110a9194b6042449431e08c4d80c0481e5891e58d429df5899690511c2"},
+ {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:556de4430ce324c836789fa4560ca62d1591d2538b8ceb0b4f68fb7b2384a27a"},
+ {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7645a8e814a3ee34a89c4a372011dcd817964ce8cb273c8ed6119d706e9613e3"},
+ {file = "frozenlist-1.4.0-cp39-cp39-win32.whl", hash = "sha256:19488c57c12d4e8095a922f328df3f179c820c212940a498623ed39160bc3c2f"},
+ {file = "frozenlist-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:6221d84d463fb110bdd7619b69cb43878a11d51cbb9394ae3105d082d5199167"},
+ {file = "frozenlist-1.4.0.tar.gz", hash = "sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251"},
]
[[package]]
name = "identify"
-version = "2.5.24"
+version = "2.5.33"
description = "File identification library for Python"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"},
- {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"},
+ {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"},
+ {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"},
]
[package.extras]
@@ -604,13 +435,13 @@ license = ["ukkonen"]
[[package]]
name = "idna"
-version = "3.4"
+version = "3.6"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.5"
files = [
- {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
- {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
+ {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"},
+ {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
]
[[package]]
@@ -637,74 +468,67 @@ files = [
[[package]]
name = "msgpack"
-version = "1.0.5"
+version = "1.0.7"
description = "MessagePack serializer"
optional = false
-python-versions = "*"
+python-versions = ">=3.8"
files = [
- {file = "msgpack-1.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:525228efd79bb831cf6830a732e2e80bc1b05436b086d4264814b4b2955b2fa9"},
- {file = "msgpack-1.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f8d8b3bf1ff2672567d6b5c725a1b347fe838b912772aa8ae2bf70338d5a198"},
- {file = "msgpack-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdc793c50be3f01106245a61b739328f7dccc2c648b501e237f0699fe1395b81"},
- {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cb47c21a8a65b165ce29f2bec852790cbc04936f502966768e4aae9fa763cb7"},
- {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e42b9594cc3bf4d838d67d6ed62b9e59e201862a25e9a157019e171fbe672dd3"},
- {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55b56a24893105dc52c1253649b60f475f36b3aa0fc66115bffafb624d7cb30b"},
- {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1967f6129fc50a43bfe0951c35acbb729be89a55d849fab7686004da85103f1c"},
- {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20a97bf595a232c3ee6d57ddaadd5453d174a52594bf9c21d10407e2a2d9b3bd"},
- {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d25dd59bbbbb996eacf7be6b4ad082ed7eacc4e8f3d2df1ba43822da9bfa122a"},
- {file = "msgpack-1.0.5-cp310-cp310-win32.whl", hash = "sha256:382b2c77589331f2cb80b67cc058c00f225e19827dbc818d700f61513ab47bea"},
- {file = "msgpack-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:4867aa2df9e2a5fa5f76d7d5565d25ec76e84c106b55509e78c1ede0f152659a"},
- {file = "msgpack-1.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9f5ae84c5c8a857ec44dc180a8b0cc08238e021f57abdf51a8182e915e6299f0"},
- {file = "msgpack-1.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e6ca5d5699bcd89ae605c150aee83b5321f2115695e741b99618f4856c50898"},
- {file = "msgpack-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5494ea30d517a3576749cad32fa27f7585c65f5f38309c88c6d137877fa28a5a"},
- {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ab2f3331cb1b54165976a9d976cb251a83183631c88076613c6c780f0d6e45a"},
- {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28592e20bbb1620848256ebc105fc420436af59515793ed27d5c77a217477705"},
- {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe5c63197c55bce6385d9aee16c4d0641684628f63ace85f73571e65ad1c1e8d"},
- {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed40e926fa2f297e8a653c954b732f125ef97bdd4c889f243182299de27e2aa9"},
- {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b2de4c1c0538dcb7010902a2b97f4e00fc4ddf2c8cda9749af0e594d3b7fa3d7"},
- {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf22a83f973b50f9d38e55c6aade04c41ddda19b00c4ebc558930d78eecc64ed"},
- {file = "msgpack-1.0.5-cp311-cp311-win32.whl", hash = "sha256:c396e2cc213d12ce017b686e0f53497f94f8ba2b24799c25d913d46c08ec422c"},
- {file = "msgpack-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c4c68d87497f66f96d50142a2b73b97972130d93677ce930718f68828b382e2"},
- {file = "msgpack-1.0.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a2b031c2e9b9af485d5e3c4520f4220d74f4d222a5b8dc8c1a3ab9448ca79c57"},
- {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f837b93669ce4336e24d08286c38761132bc7ab29782727f8557e1eb21b2080"},
- {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1d46dfe3832660f53b13b925d4e0fa1432b00f5f7210eb3ad3bb9a13c6204a6"},
- {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:366c9a7b9057e1547f4ad51d8facad8b406bab69c7d72c0eb6f529cf76d4b85f"},
- {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4c075728a1095efd0634a7dccb06204919a2f67d1893b6aa8e00497258bf926c"},
- {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:f933bbda5a3ee63b8834179096923b094b76f0c7a73c1cfe8f07ad608c58844b"},
- {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:36961b0568c36027c76e2ae3ca1132e35123dcec0706c4b7992683cc26c1320c"},
- {file = "msgpack-1.0.5-cp36-cp36m-win32.whl", hash = "sha256:b5ef2f015b95f912c2fcab19c36814963b5463f1fb9049846994b007962743e9"},
- {file = "msgpack-1.0.5-cp36-cp36m-win_amd64.whl", hash = "sha256:288e32b47e67f7b171f86b030e527e302c91bd3f40fd9033483f2cacc37f327a"},
- {file = "msgpack-1.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:137850656634abddfb88236008339fdaba3178f4751b28f270d2ebe77a563b6c"},
- {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c05a4a96585525916b109bb85f8cb6511db1c6f5b9d9cbcbc940dc6b4be944b"},
- {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a62ec00b636583e5cb6ad313bbed36bb7ead5fa3a3e38938503142c72cba4f"},
- {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef8108f8dedf204bb7b42994abf93882da1159728a2d4c5e82012edd92c9da9f"},
- {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1835c84d65f46900920b3708f5ba829fb19b1096c1800ad60bae8418652a951d"},
- {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e57916ef1bd0fee4f21c4600e9d1da352d8816b52a599c46460e93a6e9f17086"},
- {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:17358523b85973e5f242ad74aa4712b7ee560715562554aa2134d96e7aa4cbbf"},
- {file = "msgpack-1.0.5-cp37-cp37m-win32.whl", hash = "sha256:cb5aaa8c17760909ec6cb15e744c3ebc2ca8918e727216e79607b7bbce9c8f77"},
- {file = "msgpack-1.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:ab31e908d8424d55601ad7075e471b7d0140d4d3dd3272daf39c5c19d936bd82"},
- {file = "msgpack-1.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b72d0698f86e8d9ddf9442bdedec15b71df3598199ba33322d9711a19f08145c"},
- {file = "msgpack-1.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:379026812e49258016dd84ad79ac8446922234d498058ae1d415f04b522d5b2d"},
- {file = "msgpack-1.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:332360ff25469c346a1c5e47cbe2a725517919892eda5cfaffe6046656f0b7bb"},
- {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:476a8fe8fae289fdf273d6d2a6cb6e35b5a58541693e8f9f019bfe990a51e4ba"},
- {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9985b214f33311df47e274eb788a5893a761d025e2b92c723ba4c63936b69b1"},
- {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48296af57cdb1d885843afd73c4656be5c76c0c6328db3440c9601a98f303d87"},
- {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:addab7e2e1fcc04bd08e4eb631c2a90960c340e40dfc4a5e24d2ff0d5a3b3edb"},
- {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:916723458c25dfb77ff07f4c66aed34e47503b2eb3188b3adbec8d8aa6e00f48"},
- {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:821c7e677cc6acf0fd3f7ac664c98803827ae6de594a9f99563e48c5a2f27eb0"},
- {file = "msgpack-1.0.5-cp38-cp38-win32.whl", hash = "sha256:1c0f7c47f0087ffda62961d425e4407961a7ffd2aa004c81b9c07d9269512f6e"},
- {file = "msgpack-1.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:bae7de2026cbfe3782c8b78b0db9cbfc5455e079f1937cb0ab8d133496ac55e1"},
- {file = "msgpack-1.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:20c784e66b613c7f16f632e7b5e8a1651aa5702463d61394671ba07b2fc9e025"},
- {file = "msgpack-1.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:266fa4202c0eb94d26822d9bfd7af25d1e2c088927fe8de9033d929dd5ba24c5"},
- {file = "msgpack-1.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18334484eafc2b1aa47a6d42427da7fa8f2ab3d60b674120bce7a895a0a85bdd"},
- {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57e1f3528bd95cc44684beda696f74d3aaa8a5e58c816214b9046512240ef437"},
- {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:586d0d636f9a628ddc6a17bfd45aa5b5efaf1606d2b60fa5d87b8986326e933f"},
- {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a740fa0e4087a734455f0fc3abf5e746004c9da72fbd541e9b113013c8dc3282"},
- {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3055b0455e45810820db1f29d900bf39466df96ddca11dfa6d074fa47054376d"},
- {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a61215eac016f391129a013c9e46f3ab308db5f5ec9f25811e811f96962599a8"},
- {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:362d9655cd369b08fda06b6657a303eb7172d5279997abe094512e919cf74b11"},
- {file = "msgpack-1.0.5-cp39-cp39-win32.whl", hash = "sha256:ac9dd47af78cae935901a9a500104e2dea2e253207c924cc95de149606dc43cc"},
- {file = "msgpack-1.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:06f5174b5f8ed0ed919da0e62cbd4ffde676a374aba4020034da05fab67b9164"},
- {file = "msgpack-1.0.5.tar.gz", hash = "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c"},
+ {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862"},
+ {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329"},
+ {file = "msgpack-1.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b"},
+ {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6"},
+ {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee"},
+ {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d"},
+ {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d"},
+ {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1"},
+ {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681"},
+ {file = "msgpack-1.0.7-cp310-cp310-win32.whl", hash = "sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9"},
+ {file = "msgpack-1.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415"},
+ {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84"},
+ {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93"},
+ {file = "msgpack-1.0.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8"},
+ {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46"},
+ {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b"},
+ {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e"},
+ {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002"},
+ {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c"},
+ {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e"},
+ {file = "msgpack-1.0.7-cp311-cp311-win32.whl", hash = "sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1"},
+ {file = "msgpack-1.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82"},
+ {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b"},
+ {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4"},
+ {file = "msgpack-1.0.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee"},
+ {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5"},
+ {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672"},
+ {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075"},
+ {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba"},
+ {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c"},
+ {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5"},
+ {file = "msgpack-1.0.7-cp312-cp312-win32.whl", hash = "sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9"},
+ {file = "msgpack-1.0.7-cp312-cp312-win_amd64.whl", hash = "sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf"},
+ {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95"},
+ {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0"},
+ {file = "msgpack-1.0.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7"},
+ {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d"},
+ {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524"},
+ {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc"},
+ {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc"},
+ {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf"},
+ {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c"},
+ {file = "msgpack-1.0.7-cp38-cp38-win32.whl", hash = "sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2"},
+ {file = "msgpack-1.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c"},
+ {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f"},
+ {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81"},
+ {file = "msgpack-1.0.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc"},
+ {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d"},
+ {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7"},
+ {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61"},
+ {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819"},
+ {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd"},
+ {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f"},
+ {file = "msgpack-1.0.7-cp39-cp39-win32.whl", hash = "sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad"},
+ {file = "msgpack-1.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3"},
+ {file = "msgpack-1.0.7.tar.gz", hash = "sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87"},
]
[[package]]
@@ -792,48 +616,48 @@ files = [
[[package]]
name = "mypy"
-version = "1.4.0"
+version = "1.7.1"
description = "Optional static typing for Python"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "mypy-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3af348e0925a59213244f28c7c0c3a2c2088b4ba2fe9d6c8d4fbb0aba0b7d05"},
- {file = "mypy-1.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0b2e0da7ff9dd8d2066d093d35a169305fc4e38db378281fce096768a3dbdbf"},
- {file = "mypy-1.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210fe0f39ec5be45dd9d0de253cb79245f0a6f27631d62e0c9c7988be7152965"},
- {file = "mypy-1.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f7a5971490fd4a5a436e143105a1f78fa8b3fe95b30fff2a77542b4f3227a01f"},
- {file = "mypy-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:50f65f0e9985f1e50040e603baebab83efed9eb37e15a22a4246fa7cd660f981"},
- {file = "mypy-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1b5c875fcf3e7217a3de7f708166f641ca154b589664c44a6fd6d9f17d9e7e"},
- {file = "mypy-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b4c734d947e761c7ceb1f09a98359dd5666460acbc39f7d0a6b6beec373c5840"},
- {file = "mypy-1.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5984a8d13d35624e3b235a793c814433d810acba9eeefe665cdfed3d08bc3af"},
- {file = "mypy-1.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0f98973e39e4a98709546a9afd82e1ffcc50c6ec9ce6f7870f33ebbf0bd4f26d"},
- {file = "mypy-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:19d42b08c7532d736a7e0fb29525855e355fa51fd6aef4f9bbc80749ff64b1a2"},
- {file = "mypy-1.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6ba9a69172abaa73910643744d3848877d6aac4a20c41742027dcfd8d78f05d9"},
- {file = "mypy-1.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a34eed094c16cad0f6b0d889811592c7a9b7acf10d10a7356349e325d8704b4f"},
- {file = "mypy-1.4.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:53c2a1fed81e05ded10a4557fe12bae05b9ecf9153f162c662a71d924d504135"},
- {file = "mypy-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bba57b4d2328740749f676807fcf3036e9de723530781405cc5a5e41fc6e20de"},
- {file = "mypy-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:653863c75f0dbb687d92eb0d4bd9fe7047d096987ecac93bb7b1bc336de48ebd"},
- {file = "mypy-1.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7461469e163f87a087a5e7aa224102a30f037c11a096a0ceeb721cb0dce274c8"},
- {file = "mypy-1.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cf0ca95e4b8adeaf07815a78b4096b65adf64ea7871b39a2116c19497fcd0dd"},
- {file = "mypy-1.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:94a81b9354545123feb1a99b960faeff9e1fa204fce47e0042335b473d71530d"},
- {file = "mypy-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:67242d5b28ed0fa88edd8f880aed24da481929467fdbca6487167cb5e3fd31ff"},
- {file = "mypy-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3f2b353eebef669529d9bd5ae3566905a685ae98b3af3aad7476d0d519714758"},
- {file = "mypy-1.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:62bf18d97c6b089f77f0067b4e321db089d8520cdeefc6ae3ec0f873621c22e5"},
- {file = "mypy-1.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca33ab70a4aaa75bb01086a0b04f0ba8441e51e06fc57e28585176b08cad533b"},
- {file = "mypy-1.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5a0ee54c2cb0f957f8a6f41794d68f1a7e32b9968675ade5846f538504856d42"},
- {file = "mypy-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:6c34d43e3d54ad05024576aef28081d9d0580f6fa7f131255f54020eb12f5352"},
- {file = "mypy-1.4.0-py3-none-any.whl", hash = "sha256:f051ca656be0c179c735a4c3193f307d34c92fdc4908d44fd4516fbe8b10567d"},
- {file = "mypy-1.4.0.tar.gz", hash = "sha256:de1e7e68148a213036276d1f5303b3836ad9a774188961eb2684eddff593b042"},
+ {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"},
+ {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"},
+ {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"},
+ {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"},
+ {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"},
+ {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"},
+ {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"},
+ {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"},
+ {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"},
+ {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"},
+ {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"},
+ {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"},
+ {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"},
+ {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"},
+ {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"},
+ {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"},
+ {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"},
+ {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"},
+ {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"},
+ {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"},
+ {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"},
+ {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"},
+ {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"},
+ {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"},
+ {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"},
+ {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"},
+ {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"},
]
[package.dependencies]
mypy-extensions = ">=1.0.0"
-tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
-typing-extensions = ">=3.10"
+typing-extensions = ">=4.1.0"
[package.extras]
dmypy = ["psutil (>=4.0)"]
install-types = ["pip"]
-python2 = ["typed-ast (>=1.4.0,<2)"]
+mypyc = ["setuptools (>=50)"]
reports = ["lxml"]
[[package]]
@@ -863,50 +687,50 @@ setuptools = "*"
[[package]]
name = "packaging"
-version = "23.1"
+version = "23.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.7"
files = [
- {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
- {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
+ {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
+ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
]
[[package]]
name = "pathspec"
-version = "0.11.1"
+version = "0.12.1"
description = "Utility library for gitignore style pattern matching of file paths."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"},
- {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"},
+ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
+ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
]
[[package]]
name = "platformdirs"
-version = "3.6.0"
+version = "4.1.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "platformdirs-3.6.0-py3-none-any.whl", hash = "sha256:ffa199e3fbab8365778c4a10e1fbf1b9cd50707de826eb304b50e57ec0cc8d38"},
- {file = "platformdirs-3.6.0.tar.gz", hash = "sha256:57e28820ca8094678b807ff529196506d7a21e17156cb1cddb3e74cebce54640"},
+ {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"},
+ {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"},
]
[package.extras]
-docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
-test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"]
+docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
[[package]]
name = "pluggy"
-version = "1.0.0"
+version = "1.3.0"
description = "plugin and hook calling mechanisms for python"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
files = [
- {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
- {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
+ {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"},
+ {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"},
]
[package.extras]
@@ -915,13 +739,13 @@ testing = ["pytest", "pytest-benchmark"]
[[package]]
name = "pre-commit"
-version = "3.3.3"
+version = "3.6.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
files = [
- {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"},
- {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"},
+ {file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"},
+ {file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"},
]
[package.dependencies]
@@ -933,13 +757,13 @@ virtualenv = ">=20.10.0"
[[package]]
name = "py-algorand-sdk"
-version = "2.3.0"
+version = "2.5.0"
description = "Algorand SDK in Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "py-algorand-sdk-2.3.0.tar.gz", hash = "sha256:6ccd9777007b3462f44fface7a7d040b6e21e03cede9319b0242d5498499889d"},
- {file = "py_algorand_sdk-2.3.0-py3-none-any.whl", hash = "sha256:a4e0e55a488daed6262c78b5358eb90bfd465758ee345e816bb603460341d816"},
+ {file = "py-algorand-sdk-2.5.0.tar.gz", hash = "sha256:014b475595aedb82d9ac056d835f65f5ba44f6373aafef9ea4cfe515c648bcef"},
+ {file = "py_algorand_sdk-2.5.0-py3-none-any.whl", hash = "sha256:d1cb2a191edcda1e6febd2f4d830a5d441b243dfc47f9e2008630b52b2d61561"},
]
[package.dependencies]
@@ -949,13 +773,13 @@ pynacl = ">=1.4.0,<2"
[[package]]
name = "pycodestyle"
-version = "2.10.0"
+version = "2.11.1"
description = "Python style guide checker"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
files = [
- {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"},
- {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"},
+ {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"},
+ {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"},
]
[[package]]
@@ -971,54 +795,54 @@ files = [
[[package]]
name = "pycryptodomex"
-version = "3.18.0"
+version = "3.19.0"
description = "Cryptographic library for Python"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
- {file = "pycryptodomex-3.18.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:160a39a708c36fa0b168ab79386dede588e62aec06eb505add870739329aecc6"},
- {file = "pycryptodomex-3.18.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c2953afebf282a444c51bf4effe751706b4d0d63d7ca2cc51db21f902aa5b84e"},
- {file = "pycryptodomex-3.18.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:ba95abd563b0d1b88401658665a260852a8e6c647026ee6a0a65589287681df8"},
- {file = "pycryptodomex-3.18.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:192306cf881fe3467dda0e174a4f47bb3a8bb24b90c9cdfbdc248eec5fc0578c"},
- {file = "pycryptodomex-3.18.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:f9ab5ef0718f6a8716695dea16d83b671b22c45e9c0c78fd807c32c0192e54b5"},
- {file = "pycryptodomex-3.18.0-cp27-cp27m-win32.whl", hash = "sha256:50308fcdbf8345e5ec224a5502b4215178bdb5e95456ead8ab1a69ffd94779cb"},
- {file = "pycryptodomex-3.18.0-cp27-cp27m-win_amd64.whl", hash = "sha256:4d9379c684efea80fdab02a3eb0169372bca7db13f9332cb67483b8dc8b67c37"},
- {file = "pycryptodomex-3.18.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5594a125dae30d60e94f37797fc67ce3c744522de7992c7c360d02fdb34918f8"},
- {file = "pycryptodomex-3.18.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:8ff129a5a0eb5ff16e45ca4fa70a6051da7f3de303c33b259063c19be0c43d35"},
- {file = "pycryptodomex-3.18.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:3d9314ac785a5b75d5aaf924c5f21d6ca7e8df442e5cf4f0fefad4f6e284d422"},
- {file = "pycryptodomex-3.18.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:f237278836dda412a325e9340ba2e6a84cb0f56b9244781e5b61f10b3905de88"},
- {file = "pycryptodomex-3.18.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac614363a86cc53d8ba44b6c469831d1555947e69ab3276ae8d6edc219f570f7"},
- {file = "pycryptodomex-3.18.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:302a8f37c224e7b5d72017d462a2be058e28f7be627bdd854066e16722d0fc0c"},
- {file = "pycryptodomex-3.18.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:6421d23d6a648e83ba2670a352bcd978542dad86829209f59d17a3f087f4afef"},
- {file = "pycryptodomex-3.18.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84e105787f5e5d36ec6a581ff37a1048d12e638688074b2a00bcf402f9aa1c2"},
- {file = "pycryptodomex-3.18.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6875eb8666f68ddbd39097867325bd22771f595b4e2b0149739b5623c8bf899b"},
- {file = "pycryptodomex-3.18.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:27072a494ce621cc7a9096bbf60ed66826bb94db24b49b7359509e7951033e74"},
- {file = "pycryptodomex-3.18.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:1949e09ea49b09c36d11a951b16ff2a05a0ffe969dda1846e4686ee342fe8646"},
- {file = "pycryptodomex-3.18.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6ed3606832987018615f68e8ed716a7065c09a0fe94afd7c9ca1b6777f0ac6eb"},
- {file = "pycryptodomex-3.18.0-cp35-abi3-win32.whl", hash = "sha256:d56c9ec41258fd3734db9f5e4d2faeabe48644ba9ca23b18e1839b3bdf093222"},
- {file = "pycryptodomex-3.18.0-cp35-abi3-win_amd64.whl", hash = "sha256:e00a4bacb83a2627e8210cb353a2e31f04befc1155db2976e5e239dd66482278"},
- {file = "pycryptodomex-3.18.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2dc4eab20f4f04a2d00220fdc9258717b82d31913552e766d5f00282c031b70a"},
- {file = "pycryptodomex-3.18.0-pp27-pypy_73-win32.whl", hash = "sha256:75672205148bdea34669173366df005dbd52be05115e919551ee97171083423d"},
- {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bec6c80994d4e7a38312072f89458903b65ec99bed2d65aa4de96d997a53ea7a"},
- {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d35a8ffdc8b05e4b353ba281217c8437f02c57d7233363824e9d794cf753c419"},
- {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76f0a46bee539dae4b3dfe37216f678769349576b0080fdbe431d19a02da42ff"},
- {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:71687eed47df7e965f6e0bf3cadef98f368d5221f0fb89d2132effe1a3e6a194"},
- {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:73d64b32d84cf48d9ec62106aa277dbe99ab5fbfd38c5100bc7bddd3beb569f7"},
- {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbdcce0a226d9205560a5936b05208c709b01d493ed8307792075dedfaaffa5f"},
- {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58fc0aceb9c961b9897facec9da24c6a94c5db04597ec832060f53d4d6a07196"},
- {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:215be2980a6b70704c10796dd7003eb4390e7be138ac6fb8344bf47e71a8d470"},
- {file = "pycryptodomex-3.18.0.tar.gz", hash = "sha256:3e3ecb5fe979e7c1bb0027e518340acf7ee60415d79295e5251d13c68dde576e"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff64fd720def623bf64d8776f8d0deada1cc1bf1ec3c1f9d6f5bb5bd098d034f"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:61056a1fd3254f6f863de94c233b30dd33bc02f8c935b2000269705f1eeeffa4"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:258c4233a3fe5a6341780306a36c6fb072ef38ce676a6d41eec3e591347919e8"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e45bb4635b3c4e0a00ca9df75ef6295838c85c2ac44ad882410cb631ed1eeaa"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a12144d785518f6491ad334c75ccdc6ad52ea49230b4237f319dbb7cef26f464"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:1789d89f61f70a4cd5483d4dfa8df7032efab1118f8b9894faae03c967707865"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:eb2fc0ec241bf5e5ef56c8fbec4a2634d631e4c4f616a59b567947a0f35ad83c"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:c9a68a2f7bd091ccea54ad3be3e9d65eded813e6d79fdf4cc3604e26cdd6384f"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:8df69e41f7e7015a90b94d1096ec3d8e0182e73449487306709ec27379fff761"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:917033016ecc23c8933205585a0ab73e20020fdf671b7cd1be788a5c4039840b"},
+ {file = "pycryptodomex-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:e8e5ecbd4da4157889fce8ba49da74764dd86c891410bfd6b24969fa46edda51"},
+ {file = "pycryptodomex-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:a77b79852175064c822b047fee7cf5a1f434f06ad075cc9986aa1c19a0c53eb0"},
+ {file = "pycryptodomex-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5b883e1439ab63af976656446fb4839d566bb096f15fc3c06b5a99cde4927188"},
+ {file = "pycryptodomex-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3866d68e2fc345162b1b9b83ef80686acfe5cec0d134337f3b03950a0a8bf56"},
+ {file = "pycryptodomex-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74eb1f73f788facece7979ce91594dc177e1a9b5d5e3e64697dd58299e5cb4d"},
+ {file = "pycryptodomex-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cb51096a6a8d400724104db8a7e4f2206041a1f23e58924aa3d8d96bcb48338"},
+ {file = "pycryptodomex-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a588a1cb7781da9d5e1c84affd98c32aff9c89771eac8eaa659d2760666f7139"},
+ {file = "pycryptodomex-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:d4dd3b381ff5a5907a3eb98f5f6d32c64d319a840278ceea1dcfcc65063856f3"},
+ {file = "pycryptodomex-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:263de9a96d2fcbc9f5bd3a279f14ea0d5f072adb68ebd324987576ec25da084d"},
+ {file = "pycryptodomex-3.19.0-cp35-abi3-win32.whl", hash = "sha256:67c8eb79ab33d0fbcb56842992298ddb56eb6505a72369c20f60bc1d2b6fb002"},
+ {file = "pycryptodomex-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:09c9401dc06fb3d94cb1ec23b4ea067a25d1f4c6b7b118ff5631d0b5daaab3cc"},
+ {file = "pycryptodomex-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:edbe083c299835de7e02c8aa0885cb904a75087d35e7bab75ebe5ed336e8c3e2"},
+ {file = "pycryptodomex-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:136b284e9246b4ccf4f752d435c80f2c44fc2321c198505de1d43a95a3453b3c"},
+ {file = "pycryptodomex-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5d73e9fa3fe830e7b6b42afc49d8329b07a049a47d12e0ef9225f2fd220f19b2"},
+ {file = "pycryptodomex-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b2f1982c5bc311f0aab8c293524b861b485d76f7c9ab2c3ac9a25b6f7655975"},
+ {file = "pycryptodomex-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb040b5dda1dff1e197d2ef71927bd6b8bfcb9793bc4dfe0bb6df1e691eaacb"},
+ {file = "pycryptodomex-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:800a2b05cfb83654df80266692f7092eeefe2a314fa7901dcefab255934faeec"},
+ {file = "pycryptodomex-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c01678aee8ac0c1a461cbc38ad496f953f9efcb1fa19f5637cbeba7544792a53"},
+ {file = "pycryptodomex-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2126bc54beccbede6eade00e647106b4f4c21e5201d2b0a73e9e816a01c50905"},
+ {file = "pycryptodomex-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b801216c48c0886742abf286a9a6b117e248ca144d8ceec1f931ce2dd0c9cb40"},
+ {file = "pycryptodomex-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:50cb18d4dd87571006fd2447ccec85e6cec0136632a550aa29226ba075c80644"},
+ {file = "pycryptodomex-3.19.0.tar.gz", hash = "sha256:af83a554b3f077564229865c45af0791be008ac6469ef0098152139e6bd4b5b6"},
]
[[package]]
name = "pyflakes"
-version = "3.0.1"
+version = "3.1.0"
description = "passive checker of Python programs"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
files = [
- {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"},
- {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"},
+ {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"},
+ {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"},
]
[[package]]
@@ -1047,55 +871,35 @@ cffi = ">=1.4.1"
docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"]
tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"]
-[[package]]
-name = "pyteal"
-version = "0.24.1"
-description = "Algorand Smart Contracts in Python"
-optional = false
-python-versions = ">=3.10"
-files = [
- {file = "pyteal-0.24.1-py3-none-any.whl", hash = "sha256:19c601f0ea4d1a0be41a3fe48cd3807558a0e907cd47d0dca5df60977d78f2c4"},
- {file = "pyteal-0.24.1.tar.gz", hash = "sha256:172d796981f8f9d3a9a8fbe71a71a49cf185509780f46d82e29aaa692386d1fa"},
-]
-
-[package.dependencies]
-docstring-parser = "0.14.1"
-executing = "1.2.0"
-py-algorand-sdk = ">=2.0.0,<3.0.0"
-semantic-version = ">=2.9.0,<3.0.0"
-tabulate = ">=0.9.0,<0.10.0"
-
[[package]]
name = "pytest"
-version = "7.3.2"
+version = "7.4.3"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.7"
files = [
- {file = "pytest-7.3.2-py3-none-any.whl", hash = "sha256:cdcbd012c9312258922f8cd3f1b62a6580fdced17db6014896053d47cddf9295"},
- {file = "pytest-7.3.2.tar.gz", hash = "sha256:ee990a3cc55ba808b80795a79944756f315c67c12b56abd3ac993a7b8c17030b"},
+ {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"},
+ {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"},
]
[package.dependencies]
colorama = {version = "*", markers = "sys_platform == \"win32\""}
-exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=0.12,<2.0"
-tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
[package.extras]
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
[[package]]
name = "pytest-xdist"
-version = "3.3.1"
+version = "3.5.0"
description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs"
optional = false
python-versions = ">=3.7"
files = [
- {file = "pytest-xdist-3.3.1.tar.gz", hash = "sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93"},
- {file = "pytest_xdist-3.3.1-py3-none-any.whl", hash = "sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2"},
+ {file = "pytest-xdist-3.5.0.tar.gz", hash = "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a"},
+ {file = "pytest_xdist-3.5.0-py3-none-any.whl", hash = "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24"},
]
[package.dependencies]
@@ -1123,258 +927,313 @@ cli = ["click (>=5.0)"]
[[package]]
name = "pyyaml"
-version = "6.0"
+version = "6.0.1"
description = "YAML parser and emitter for Python"
optional = false
python-versions = ">=3.6"
files = [
- {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
- {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
- {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
- {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
- {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
- {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
- {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
- {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
- {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
- {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
- {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
- {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
- {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
- {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
- {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
- {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
- {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
- {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
- {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
- {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
- {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
- {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
- {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
- {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
- {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
- {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
- {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
- {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
- {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
- {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
- {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
- {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
- {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
- {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
- {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
- {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
- {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
- {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
- {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
- {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
+ {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
+ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
]
[[package]]
name = "ruff"
-version = "0.1.6"
+version = "0.1.7"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
- {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:88b8cdf6abf98130991cbc9f6438f35f6e8d41a02622cc5ee130a02a0ed28703"},
- {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c549ed437680b6105a1299d2cd30e4964211606eeb48a0ff7a93ef70b902248"},
- {file = "ruff-0.1.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cf5f701062e294f2167e66d11b092bba7af6a057668ed618a9253e1e90cfd76"},
- {file = "ruff-0.1.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:05991ee20d4ac4bb78385360c684e4b417edd971030ab12a4fbd075ff535050e"},
- {file = "ruff-0.1.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87455a0c1f739b3c069e2f4c43b66479a54dea0276dd5d4d67b091265f6fd1dc"},
- {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:683aa5bdda5a48cb8266fcde8eea2a6af4e5700a392c56ea5fb5f0d4bfdc0240"},
- {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:137852105586dcbf80c1717facb6781555c4e99f520c9c827bd414fac67ddfb6"},
- {file = "ruff-0.1.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd98138a98d48a1c36c394fd6b84cd943ac92a08278aa8ac8c0fdefcf7138f35"},
- {file = "ruff-0.1.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0cd909d25f227ac5c36d4e7e681577275fb74ba3b11d288aff7ec47e3ae745"},
- {file = "ruff-0.1.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8fd1c62a47aa88a02707b5dd20c5ff20d035d634aa74826b42a1da77861b5ff"},
- {file = "ruff-0.1.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fd89b45d374935829134a082617954120d7a1470a9f0ec0e7f3ead983edc48cc"},
- {file = "ruff-0.1.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:491262006e92f825b145cd1e52948073c56560243b55fb3b4ecb142f6f0e9543"},
- {file = "ruff-0.1.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ea284789861b8b5ca9d5443591a92a397ac183d4351882ab52f6296b4fdd5462"},
- {file = "ruff-0.1.6-py3-none-win32.whl", hash = "sha256:1610e14750826dfc207ccbcdd7331b6bd285607d4181df9c1c6ae26646d6848a"},
- {file = "ruff-0.1.6-py3-none-win_amd64.whl", hash = "sha256:4558b3e178145491e9bc3b2ee3c4b42f19d19384eaa5c59d10acf6e8f8b57e33"},
- {file = "ruff-0.1.6-py3-none-win_arm64.whl", hash = "sha256:03910e81df0d8db0e30050725a5802441c2022ea3ae4fe0609b76081731accbc"},
- {file = "ruff-0.1.6.tar.gz", hash = "sha256:1b09f29b16c6ead5ea6b097ef2764b42372aebe363722f1605ecbcd2b9207184"},
+ {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7f80496854fdc65b6659c271d2c26e90d4d401e6a4a31908e7e334fab4645aac"},
+ {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1ea109bdb23c2a4413f397ebd8ac32cb498bee234d4191ae1a310af760e5d287"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0c2de9dd9daf5e07624c24add25c3a490dbf74b0e9bca4145c632457b3b42a"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69a4bed13bc1d5dabf3902522b5a2aadfebe28226c6269694283c3b0cecb45fd"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de02ca331f2143195a712983a57137c5ec0f10acc4aa81f7c1f86519e52b92a1"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45b38c3f8788a65e6a2cab02e0f7adfa88872696839d9882c13b7e2f35d64c5f"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c64cb67b2025b1ac6d58e5ffca8f7b3f7fd921f35e78198411237e4f0db8e73"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dcc6bb2f4df59cb5b4b40ff14be7d57012179d69c6565c1da0d1f013d29951b"},
+ {file = "ruff-0.1.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2bb4bb6bbe921f6b4f5b6fdd8d8468c940731cb9406f274ae8c5ed7a78c478"},
+ {file = "ruff-0.1.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:276a89bcb149b3d8c1b11d91aa81898fe698900ed553a08129b38d9d6570e717"},
+ {file = "ruff-0.1.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:90c958fe950735041f1c80d21b42184f1072cc3975d05e736e8d66fc377119ea"},
+ {file = "ruff-0.1.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b05e3b123f93bb4146a761b7a7d57af8cb7384ccb2502d29d736eaade0db519"},
+ {file = "ruff-0.1.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:290ecab680dce94affebefe0bbca2322a6277e83d4f29234627e0f8f6b4fa9ce"},
+ {file = "ruff-0.1.7-py3-none-win32.whl", hash = "sha256:416dfd0bd45d1a2baa3b1b07b1b9758e7d993c256d3e51dc6e03a5e7901c7d80"},
+ {file = "ruff-0.1.7-py3-none-win_amd64.whl", hash = "sha256:4af95fd1d3b001fc41325064336db36e3d27d2004cdb6d21fd617d45a172dd96"},
+ {file = "ruff-0.1.7-py3-none-win_arm64.whl", hash = "sha256:0683b7bfbb95e6df3c7c04fe9d78f631f8e8ba4868dfc932d43d690698057e2e"},
+ {file = "ruff-0.1.7.tar.gz", hash = "sha256:dffd699d07abf54833e5f6cc50b85a6ff043715da8788c4a79bcd4ab4734d306"},
]
-[[package]]
-name = "semantic-version"
-version = "2.10.0"
-description = "A library implementing the 'SemVer' scheme."
-optional = false
-python-versions = ">=2.7"
-files = [
- {file = "semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177"},
- {file = "semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c"},
-]
-
-[package.extras]
-dev = ["Django (>=1.11)", "check-manifest", "colorama (<=0.4.1)", "coverage", "flake8", "nose2", "readme-renderer (<25.0)", "tox", "wheel", "zest.releaser[recommended]"]
-doc = ["Sphinx", "sphinx-rtd-theme"]
-
[[package]]
name = "setuptools"
-version = "68.0.0"
+version = "69.0.2"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
-python-versions = ">=3.7"
-files = [
- {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"},
- {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"},
-]
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
-testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
-testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
-
-[[package]]
-name = "tabulate"
-version = "0.9.0"
-description = "Pretty-print tabular data"
-optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"},
- {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"},
+ {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"},
+ {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"},
]
[package.extras]
-widechars = ["wcwidth"]
-
-[[package]]
-name = "tomli"
-version = "2.0.1"
-description = "A lil' TOML parser"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
- {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
-]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
+testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
name = "types-pyyaml"
-version = "6.0.12.10"
+version = "6.0.12.12"
description = "Typing stubs for PyYAML"
optional = false
python-versions = "*"
files = [
- {file = "types-PyYAML-6.0.12.10.tar.gz", hash = "sha256:ebab3d0700b946553724ae6ca636ea932c1b0868701d4af121630e78d695fc97"},
- {file = "types_PyYAML-6.0.12.10-py3-none-any.whl", hash = "sha256:662fa444963eff9b68120d70cda1af5a5f2aa57900003c2006d7626450eaae5f"},
+ {file = "types-PyYAML-6.0.12.12.tar.gz", hash = "sha256:334373d392fde0fdf95af5c3f1661885fa10c52167b14593eb856289e1855062"},
+ {file = "types_PyYAML-6.0.12.12-py3-none-any.whl", hash = "sha256:c05bc6c158facb0676674b7f11fe3960db4f389718e19e62bd2b84d6205cfd24"},
]
[[package]]
name = "typing-extensions"
-version = "4.6.3"
-description = "Backported and Experimental Type Hints for Python 3.7+"
+version = "4.9.0"
+description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"},
- {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"},
+ {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"},
+ {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"},
]
[[package]]
name = "virtualenv"
-version = "20.23.1"
+version = "20.25.0"
description = "Virtual Python Environment builder"
optional = false
python-versions = ">=3.7"
files = [
- {file = "virtualenv-20.23.1-py3-none-any.whl", hash = "sha256:34da10f14fea9be20e0fd7f04aba9732f84e593dac291b757ce42e3368a39419"},
- {file = "virtualenv-20.23.1.tar.gz", hash = "sha256:8ff19a38c1021c742148edc4f81cb43d7f8c6816d2ede2ab72af5b84c749ade1"},
+ {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"},
+ {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"},
]
[package.dependencies]
-distlib = ">=0.3.6,<1"
-filelock = ">=3.12,<4"
-platformdirs = ">=3.5.1,<4"
+distlib = ">=0.3.7,<1"
+filelock = ">=3.12.2,<4"
+platformdirs = ">=3.9.1,<5"
[package.extras]
-docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
-test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezer (>=0.4.6)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.8)", "time-machine (>=2.9)"]
+docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
+test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
+
+[[package]]
+name = "wrapt"
+version = "1.16.0"
+description = "Module for decorators, wrappers and monkey patching."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"},
+ {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"},
+ {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"},
+ {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"},
+ {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"},
+ {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"},
+ {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"},
+ {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"},
+ {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"},
+ {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"},
+ {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"},
+ {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"},
+ {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"},
+ {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"},
+ {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"},
+ {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"},
+ {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"},
+ {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"},
+ {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"},
+ {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"},
+ {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"},
+ {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"},
+ {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"},
+ {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"},
+ {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"},
+ {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"},
+ {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"},
+ {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"},
+ {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"},
+ {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"},
+ {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"},
+ {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"},
+ {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"},
+ {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"},
+ {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"},
+ {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"},
+ {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"},
+ {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"},
+ {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"},
+ {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"},
+ {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"},
+ {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"},
+ {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"},
+ {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"},
+ {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"},
+ {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"},
+ {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"},
+ {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"},
+ {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"},
+ {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"},
+ {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"},
+ {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"},
+ {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"},
+ {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"},
+ {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"},
+ {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"},
+ {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"},
+ {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"},
+ {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"},
+ {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"},
+ {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"},
+ {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"},
+ {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"},
+ {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"},
+ {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"},
+ {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"},
+ {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"},
+ {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"},
+ {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"},
+ {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"},
+]
[[package]]
name = "yarl"
-version = "1.9.2"
+version = "1.9.4"
description = "Yet another URL library"
optional = false
python-versions = ">=3.7"
files = [
- {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82"},
- {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8"},
- {file = "yarl-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9"},
- {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560"},
- {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac"},
- {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea"},
- {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608"},
- {file = "yarl-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5"},
- {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0"},
- {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4"},
- {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095"},
- {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3"},
- {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528"},
- {file = "yarl-1.9.2-cp310-cp310-win32.whl", hash = "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3"},
- {file = "yarl-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde"},
- {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6"},
- {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb"},
- {file = "yarl-1.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0"},
- {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2"},
- {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191"},
- {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d"},
- {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7"},
- {file = "yarl-1.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6"},
- {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8"},
- {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9"},
- {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be"},
- {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7"},
- {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a"},
- {file = "yarl-1.9.2-cp311-cp311-win32.whl", hash = "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8"},
- {file = "yarl-1.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051"},
- {file = "yarl-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74"},
- {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367"},
- {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef"},
- {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3"},
- {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938"},
- {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc"},
- {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33"},
- {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45"},
- {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185"},
- {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04"},
- {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582"},
- {file = "yarl-1.9.2-cp37-cp37m-win32.whl", hash = "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b"},
- {file = "yarl-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368"},
- {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac"},
- {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4"},
- {file = "yarl-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574"},
- {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb"},
- {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59"},
- {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e"},
- {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417"},
- {file = "yarl-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78"},
- {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333"},
- {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c"},
- {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5"},
- {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc"},
- {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b"},
- {file = "yarl-1.9.2-cp38-cp38-win32.whl", hash = "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"},
- {file = "yarl-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72"},
- {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9"},
- {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8"},
- {file = "yarl-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7"},
- {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716"},
- {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a"},
- {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3"},
- {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955"},
- {file = "yarl-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1"},
- {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4"},
- {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6"},
- {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf"},
- {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3"},
- {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80"},
- {file = "yarl-1.9.2-cp39-cp39-win32.whl", hash = "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623"},
- {file = "yarl-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18"},
- {file = "yarl-1.9.2.tar.gz", hash = "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"},
+ {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"},
+ {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"},
+ {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"},
+ {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"},
+ {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"},
+ {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"},
+ {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"},
+ {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"},
+ {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"},
+ {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"},
+ {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"},
+ {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"},
+ {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"},
+ {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"},
+ {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"},
+ {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"},
+ {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"},
+ {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"},
+ {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"},
+ {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"},
+ {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"},
+ {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"},
+ {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"},
+ {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"},
+ {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"},
+ {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"},
+ {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"},
+ {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"},
+ {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"},
+ {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"},
+ {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"},
+ {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"},
+ {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"},
+ {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"},
+ {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"},
+ {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"},
+ {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"},
+ {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"},
+ {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"},
+ {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"},
+ {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"},
+ {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"},
+ {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"},
+ {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"},
+ {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"},
+ {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"},
+ {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"},
+ {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"},
+ {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"},
+ {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"},
+ {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"},
+ {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"},
+ {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"},
+ {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"},
+ {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"},
+ {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"},
+ {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"},
+ {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"},
+ {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"},
+ {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"},
+ {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"},
+ {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"},
+ {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"},
+ {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"},
+ {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"},
+ {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"},
+ {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"},
+ {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"},
+ {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"},
+ {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"},
+ {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"},
+ {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"},
+ {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"},
+ {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"},
+ {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"},
+ {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"},
+ {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"},
+ {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"},
+ {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"},
+ {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"},
+ {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"},
+ {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"},
+ {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"},
+ {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"},
+ {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"},
+ {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"},
+ {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"},
+ {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"},
+ {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"},
+ {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"},
]
[package.dependencies]
@@ -1383,5 +1242,5 @@ multidict = ">=4.0"
[metadata]
lock-version = "2.0"
-python-versions = "^3.10"
-content-hash = "a1be7e90d0aa7be5d883b5f4f298f12b7b4d98b2bd136f09f449b522347cc385"
+python-versions = "^3.12"
+content-hash = "34d5c5b0f30e60912104d8a255f2de9df3e5643e09b808ba560bece55ee0b563"
diff --git a/pyproject.toml b/pyproject.toml
index 4ac1b7e..e627908 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,14 +6,13 @@ authors = ["MakerX "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.0.0"
+python = "^3.12"
algokit-utils = "^1.3"
python-dotenv = "^1.0.0"
[tool.poetry.group.dev.dependencies]
ruff = "^0.1.6"
-black = {extras = ["d"], version = "^22.10.0"}
+black = { extras = ["d"], version = "^22.10.0" }
flake8 = "^6.0.0"
pytest = "^7.2.2"
mypy = "^1.1.1"
@@ -26,39 +25,52 @@ requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.ruff]
-select = ["E", "F", "ANN", "UP", "N", "C4", "B", "A", "YTT", "W", "FBT", "Q", "RUF", "I"]
+select = [
+ "E",
+ "F",
+ "ANN",
+ "UP",
+ "N",
+ "C4",
+ "B",
+ "A",
+ "YTT",
+ "W",
+ "FBT",
+ "Q",
+ "RUF",
+ "I",
+]
extend-exclude = [
"tests_generated/*", # Ignoring generated tests, ruff specific errors are to be caught by pytest
"template_content",
".git",
".mypy_cache",
".ruff_cache",
- ]
+]
ignore = [
"ANN101", # no type for self
"ANN102", # no type for cls
"RET505", # allow else after return
"SIM108", # allow if-else in place of ternary
- "E111", # indentation is not a multiple of four
- "E117", # over-indented
+ "E111", # indentation is not a multiple of four
+ "E117", # over-indented
"ISC001", # single line implicit string concatenation
"ISC002", # multi line implicit string concatenation
- "Q000", # bad quotes inline string
- "Q001", # bad quotes multiline string
- "Q002", # bad quotes docstring
- "Q003", # avoidable escaped quotes
- "W191", # indentation contains tabs
+ "Q000", # bad quotes inline string
+ "Q001", # bad quotes multiline string
+ "Q002", # bad quotes docstring
+ "Q003", # avoidable escaped quotes
+ "W191", # indentation contains tabs
]
unfixable = ["B", "RUF"]
[tool.pytest.ini_options]
pythonpath = ["tests"]
-testpaths = [
- "tests",
-]
+testpaths = ["tests"]
[tool.mypy]
-python_version = "3.10"
+python_version = "3.12"
check_untyped_defs = true
warn_redundant_casts = true
warn_unused_ignores = true
diff --git a/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/contract.py.j2 b/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/contract.py.j2
index 01e5881..83b938b 100644
--- a/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/contract.py.j2
+++ b/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/contract.py.j2
@@ -1,30 +1,8 @@
-import beaker
-import pyteal as pt
-{% if preset_name == 'starter' %}
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("{{ contract_name }}")
-{% elif preset_name == 'production' -%}
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
-app = beaker.Application("{{ contract_name }}")
-
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-{% endif %}
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class {{ contract_name.split('_')|map('capitalize')|join }}(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/{% if deployment_language == 'python' %}deploy_config.py.j2{% endif %}.jinja b/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/{% if deployment_language == 'python' %}deploy_config.py.j2{% endif %}.jinja
index c86ec1f..7d4017a 100644
--- a/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/{% if deployment_language == 'python' %}deploy_config.py.j2{% endif %}.jinja
+++ b/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/{% if deployment_language == 'python' %}deploy_config.py.j2{% endif %}.jinja
@@ -1,4 +1,3 @@
-{% raw -%}
import logging
import algokit_utils
@@ -24,33 +23,13 @@ def deploy(
creator=deployer,
indexer_client=indexer_client,
)
-
-
- {%- if preset_name == 'starter' %}
app_client.deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
- {%- elif preset_name == 'production' %}
- is_mainnet = algokit_utils.is_mainnet(algod_client)
- app_client.deploy(
- on_schema_break=(
- algokit_utils.OnSchemaBreak.AppendApp
- if is_mainnet
- else algokit_utils.OnSchemaBreak.ReplaceApp
- ),
- on_update=algokit_utils.OnUpdate.AppendApp
- if is_mainnet
- else algokit_utils.OnUpdate.UpdateApp,
- allow_delete=not is_mainnet,
- allow_update=not is_mainnet,
- )
- {%- endif %}
-
name = "world"
response = app_client.hello(name=name)
logger.info(
f"Called hello on {app_spec.contract.name} ({app_client.app_id}) "
f"with name={name}, received: {response.return_value}"
)
-{% endraw -%}
diff --git a/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/{% if deployment_language == 'typescript' %}deploy-config.ts.j2{% endif %}.jinja b/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/{% if deployment_language == 'typescript' %}deploy-config.ts.j2{% endif %}.jinja
index dddaad1..e8c272e 100644
--- a/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/{% if deployment_language == 'typescript' %}deploy-config.ts.j2{% endif %}.jinja
+++ b/template_content/.algokit/generators/create_contract/smart_contracts/{% raw %}{{ contract_name }}{% endraw %}/{% if deployment_language == 'typescript' %}deploy-config.ts.j2{% endif %}.jinja
@@ -1,4 +1,3 @@
-{% raw -%}
import * as algokit from '@algorandfoundation/algokit-utils'
import { {{ contract_name.split('_')|map('capitalize')|join }}Client } from '../artifacts/{{ contract_name }}/client'
@@ -27,20 +26,11 @@ export async function deploy() {
algod,
)
- {%- if preset_name == 'starter' %}
const app = await appClient.deploy({
onSchemaBreak: 'append',
onUpdate: 'append',
})
- {% elif preset_name == 'production' %}
- const isMainNet = await algokit.isMainNet(algod)
- const app = await appClient.deploy({
- allowDelete: !isMainNet,
- allowUpdate: !isMainNet,
- onSchemaBreak: isMainNet ? 'append' : 'replace',
- onUpdate: isMainNet ? 'append' : 'update',
- })
- {% endif %}
+
// If app was just created fund the app account
if (['create', 'replace'].includes(app.operationPerformed)) {
@@ -58,4 +48,3 @@ export async function deploy() {
const response = await appClient.hello({ name: 'world' })
console.log(`Called ${method} on ${app.name} (${app.appId}) with name = world, received: ${response.return}`)
}
-{% endraw -%}
diff --git a/template_content/README.md.jinja b/template_content/README.md.jinja
index 06106cf..341120b 100644
--- a/template_content/README.md.jinja
+++ b/template_content/README.md.jinja
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -112,7 +119,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils]({% if deployment_language == "typescript" %}https://github.com/algorandfoundation/algokit-utils-ts{% else %}https://github.com/algorandfoundation/algokit-utils-py{% endif %}) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.
diff --git a/template_content/pyproject.toml.jinja b/template_content/pyproject.toml.jinja
index 5879dc5..4febe86 100644
--- a/template_content/pyproject.toml.jinja
+++ b/template_content/pyproject.toml.jinja
@@ -6,10 +6,10 @@ authors = ["{{ author_name }} <{{ author_email }}>"]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
{% if use_python_black -%}
@@ -58,7 +58,7 @@ pythonpath = ["smart_contracts", "tests"]
{% if use_python_mypy %}
[tool.mypy]
files = "smart_contracts/"
-python_version = "3.10"
+python_version = "3.12"
check_untyped_defs = true
warn_redundant_casts = true
warn_unused_ignores = true
diff --git a/template_content/smart_contracts/__main__.py.jinja b/template_content/smart_contracts/__main__.py.jinja
index 669b12e..0ab813e 100644
--- a/template_content/smart_contracts/__main__.py.jinja
+++ b/template_content/smart_contracts/__main__.py.jinja
@@ -26,20 +26,20 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
{%- if deployment_language == 'python' %}
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
{%- endif %}
diff --git a/template_content/smart_contracts/config.py.jinja b/template_content/smart_contracts/config.py.jinja
index 8cefdd6..9c9076a 100644
--- a/template_content/smart_contracts/config.py.jinja
+++ b/template_content/smart_contracts/config.py.jinja
@@ -6,26 +6,24 @@ from pathlib import Path
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/template_content/smart_contracts/helpers/build.py.jinja b/template_content/smart_contracts/helpers/build.py.jinja
index 7dc047b..8dd7f79 100644
--- a/template_content/smart_contracts/helpers/build.py.jinja
+++ b/template_content/smart_contracts/helpers/build.py.jinja
@@ -3,8 +3,6 @@ import subprocess
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
{% if deployment_language == 'python' -%}
deployment_extension = "py"
@@ -12,16 +10,30 @@ deployment_extension = "py"
deployment_extension = "ts"
{% endif %}
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -34,13 +46,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/template_content/smart_contracts/{{ contract_name }}/contract.py.jinja b/template_content/smart_contracts/{{ contract_name }}/contract.py.jinja
index 01e5881..83b938b 100644
--- a/template_content/smart_contracts/{{ contract_name }}/contract.py.jinja
+++ b/template_content/smart_contracts/{{ contract_name }}/contract.py.jinja
@@ -1,30 +1,8 @@
-import beaker
-import pyteal as pt
-{% if preset_name == 'starter' %}
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("{{ contract_name }}")
-{% elif preset_name == 'production' -%}
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
-app = beaker.Application("{{ contract_name }}")
-
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-{% endif %}
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class {{ contract_name.split('_')|map('capitalize')|join }}(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/template_content/smart_contracts/{{ contract_name }}/{% if deployment_language == 'python' %}deploy_config.py{% endif %}.jinja b/template_content/smart_contracts/{{ contract_name }}/{% if deployment_language == 'python' %}deploy_config.py{% endif %}.jinja
index bb169ac..7d4017a 100644
--- a/template_content/smart_contracts/{{ contract_name }}/{% if deployment_language == 'python' %}deploy_config.py{% endif %}.jinja
+++ b/template_content/smart_contracts/{{ contract_name }}/{% if deployment_language == 'python' %}deploy_config.py{% endif %}.jinja
@@ -23,29 +23,10 @@ def deploy(
creator=deployer,
indexer_client=indexer_client,
)
-
-
- {%- if preset_name == 'starter' %}
app_client.deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
- {%- elif preset_name == 'production' %}
- is_mainnet = algokit_utils.is_mainnet(algod_client)
- app_client.deploy(
- on_schema_break=(
- algokit_utils.OnSchemaBreak.AppendApp
- if is_mainnet
- else algokit_utils.OnSchemaBreak.ReplaceApp
- ),
- on_update=algokit_utils.OnUpdate.AppendApp
- if is_mainnet
- else algokit_utils.OnUpdate.UpdateApp,
- allow_delete=not is_mainnet,
- allow_update=not is_mainnet,
- )
- {%- endif %}
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/template_content/smart_contracts/{{ contract_name }}/{% if deployment_language == 'typescript' %}deploy-config.ts{% endif %}.jinja b/template_content/smart_contracts/{{ contract_name }}/{% if deployment_language == 'typescript' %}deploy-config.ts{% endif %}.jinja
index 325fb24..e8c272e 100644
--- a/template_content/smart_contracts/{{ contract_name }}/{% if deployment_language == 'typescript' %}deploy-config.ts{% endif %}.jinja
+++ b/template_content/smart_contracts/{{ contract_name }}/{% if deployment_language == 'typescript' %}deploy-config.ts{% endif %}.jinja
@@ -26,20 +26,11 @@ export async function deploy() {
algod,
)
- {%- if preset_name == 'starter' %}
const app = await appClient.deploy({
onSchemaBreak: 'append',
onUpdate: 'append',
})
- {% elif preset_name == 'production' %}
- const isMainNet = await algokit.isMainNet(algod)
- const app = await appClient.deploy({
- allowDelete: !isMainNet,
- allowUpdate: !isMainNet,
- onSchemaBreak: isMainNet ? 'append' : 'replace',
- onUpdate: isMainNet ? 'append' : 'update',
- })
- {% endif %}
+
// If app was just created fund the app account
if (['create', 'replace'].includes(app.operationPerformed)) {
diff --git a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/Build_Beaker_application.xml.jinja b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/Build_Beaker_application.xml.jinja
index d4b8841..67a891d 100644
--- a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/Build_Beaker_application.xml.jinja
+++ b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/Build_Beaker_application.xml.jinja
@@ -1,5 +1,5 @@
-
+
diff --git a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/Build_Beaker_application____LocalNet.xml.jinja b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/Build_Beaker_application____LocalNet.xml.jinja
index a2b0f2a..cfb969d 100644
--- a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/Build_Beaker_application____LocalNet.xml.jinja
+++ b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/Build_Beaker_application____LocalNet.xml.jinja
@@ -1,5 +1,5 @@
-
+
diff --git a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'python' %}Build___Deploy_Beaker_application.xml{% endif %}.jinja b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'python' %}Build___Deploy_Beaker_application.xml{% endif %}.jinja
index ad46e78..975b949 100644
--- a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'python' %}Build___Deploy_Beaker_application.xml{% endif %}.jinja
+++ b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'python' %}Build___Deploy_Beaker_application.xml{% endif %}.jinja
@@ -1,5 +1,5 @@
-
+
diff --git a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'python' %}Deploy_Built_Beaker_application.xml{% endif %}.jinja b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'python' %}Deploy_Built_Beaker_application.xml{% endif %}.jinja
index ac77102..05902f9 100644
--- a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'python' %}Deploy_Built_Beaker_application.xml{% endif %}.jinja
+++ b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'python' %}Deploy_Built_Beaker_application.xml{% endif %}.jinja
@@ -1,5 +1,5 @@
-
+
diff --git a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'typescript' %}Build___Deploy_Beaker_application.xml{% endif %}.jinja b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'typescript' %}Build___Deploy_Beaker_application.xml{% endif %}.jinja
index 44d3796..91067d5 100644
--- a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'typescript' %}Build___Deploy_Beaker_application.xml{% endif %}.jinja
+++ b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'typescript' %}Build___Deploy_Beaker_application.xml{% endif %}.jinja
@@ -1,5 +1,5 @@
-
+
@@ -12,7 +12,7 @@
-
+
diff --git a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'typescript' %}Deploy_Built_Beaker_application.xml{% endif %}.jinja b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'typescript' %}Deploy_Built_Beaker_application.xml{% endif %}.jinja
index b8842d9..05dd5d8 100644
--- a/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'typescript' %}Deploy_Built_Beaker_application.xml{% endif %}.jinja
+++ b/template_content/{% if ide_jetbrains %}.idea{% endif %}/runConfigurations/{% if deployment_language == 'typescript' %}Deploy_Built_Beaker_application.xml{% endif %}.jinja
@@ -1,5 +1,5 @@
-
+
diff --git a/template_content/{% if ide_vscode %}.vscode{% endif %}/launch.json.jinja b/template_content/{% if ide_vscode %}.vscode{% endif %}/launch.json.jinja
index 4b88a5c..e4ffc92 100644
--- a/template_content/{% if ide_vscode %}.vscode{% endif %}/launch.json.jinja
+++ b/template_content/{% if ide_vscode %}.vscode{% endif %}/launch.json.jinja
@@ -3,7 +3,7 @@
"configurations": [
{% if deployment_language == 'python' -%}
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -12,7 +12,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -22,7 +22,7 @@
},
{% elif deployment_language == 'typescript' -%}
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
@@ -30,11 +30,11 @@
"cwd": "${workspaceFolder}/smart_contracts",
"console": "integratedTerminal",
"skipFiles": ["/**", "node_modules/**"],
- "preLaunchTask": "Build Beaker application (+ LocalNet)",
+ "preLaunchTask": "Build Puya application (+ LocalNet)",
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
@@ -46,7 +46,7 @@
},
{% endif -%}
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/template_content/{% if ide_vscode %}.vscode{% endif %}/tasks.json b/template_content/{% if ide_vscode %}.vscode{% endif %}/tasks.json
index fe7889a..4873ec8 100644
--- a/template_content/{% if ide_vscode %}.vscode{% endif %}/tasks.json
+++ b/template_content/{% if ide_vscode %}.vscode{% endif %}/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/cd.yaml.jinja b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/cd.yaml.jinja
index 40ec64a..9431a09 100644
--- a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/cd.yaml.jinja
+++ b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/cd.yaml.jinja
@@ -23,10 +23,10 @@ jobs:
- name: Install poetry
run: pipx install poetry
- - name: Set up Python 3.10
+ - name: Set up Python 3.12
uses: actions/setup-python@v4
with:
- python-version: '3.10'
+ python-version: '3.12'
cache: 'poetry'
- name: Install algokit
diff --git a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/checks.yaml.jinja b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/checks.yaml.jinja
index edd56e6..a4b39c0 100644
--- a/template_content/{% if use_github_actions %}.github{% endif %}/workflows/checks.yaml.jinja
+++ b/template_content/{% if use_github_actions %}.github{% endif %}/workflows/checks.yaml.jinja
@@ -13,10 +13,10 @@ jobs:
- name: Install poetry
run: pipx install poetry
- - name: Set up Python 3.10
+ - name: Set up Python 3.12
uses: actions/setup-python@v4
with:
- python-version: '3.10'
+ python-version: '3.12'
cache: 'poetry'
- name: Install algokit
diff --git a/template_content/{% if use_python_pytest %}tests{% endif %}/{% if use_python_pytest %}{{ contract_name }}_test.py{% endif %}.jinja b/template_content/{% if use_python_pytest %}tests{% endif %}/{% if use_python_pytest %}{{ contract_name }}_test.py{% endif %}.jinja
index 49a75ad..62bf2ff 100644
--- a/template_content/{% if use_python_pytest %}tests{% endif %}/{% if use_python_pytest %}{{ contract_name }}_test.py{% endif %}.jinja
+++ b/template_content/{% if use_python_pytest %}tests{% endif %}/{% if use_python_pytest %}{{ contract_name }}_test.py{% endif %}.jinja
@@ -1,36 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.{{ contract_name }} import contract as {{ contract_name }}_contract
-
-
-@pytest.fixture(scope="session")
-def {{ contract_name }}_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return {{ contract_name }}_contract.app.build(algod_client)
+from smart_contracts.artifacts.{{ contract_name }}.client import {{ contract_name.split('_')|map('capitalize')|join }}Client
@pytest.fixture(scope="session")
def {{ contract_name }}_client(
- algod_client: AlgodClient, {{ contract_name }}_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> {{ contract_name.split('_')|map('capitalize')|join }}Client:
+ client = {{ contract_name.split('_')|map('capitalize')|join }}Client(
algod_client,
- app_spec={{ contract_name }}_app_spec,
- signer=get_localnet_default_account(algod_client),
- {%- if preset_name == 'production' %}
- template_values={"UPDATABLE": 1, "DELETABLE": 1},
- {%- endif %}
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello({{ contract_name }}_client: ApplicationClient) -> None:
- result = {{ contract_name }}_client.call({{ contract_name }}_contract.hello, name="World")
+def test_says_hello({{ contract_name }}_client: {{ contract_name.split('_')|map('capitalize')|join }}Client) -> None:
+ result = {{ contract_name }}_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests/test_generators.py b/tests/test_generators.py
index 4996189..6b793af 100644
--- a/tests/test_generators.py
+++ b/tests/test_generators.py
@@ -120,13 +120,7 @@ def check_codebase(working_dir: Path, test_name: str) -> subprocess.CompletedPro
content = src_path_pattern.sub("_src_path: ", content)
copier_answers.write_text(content, "utf-8")
- check_args = [BLACK_ARGS]
-
- # Starter template does not have ruff config or mypy config by default
- # so only check for them if the starter template is not used
- processed_questions = _load_copier_yaml(copier_answers)
- if processed_questions["preset_name"] == "production":
- check_args += [RUFF_ARGS, MYPY_ARGS]
+ check_args = [BLACK_ARGS, RUFF_ARGS, MYPY_ARGS]
for check_arg in check_args:
result = subprocess.run(
diff --git a/tests/test_templates.py b/tests/test_templates.py
index 0771ec2..d76892e 100644
--- a/tests/test_templates.py
+++ b/tests/test_templates.py
@@ -116,13 +116,7 @@ def run_init(
content = src_path_pattern.sub("_src_path: ", content)
copier_answers.write_text(content, "utf-8")
- check_args = [BLACK_ARGS]
-
- # Starter template does not have ruff config or mypy config by default
- # so only check for them if the starter template is not used
- processed_questions = _load_copier_yaml(copier_answers)
- if processed_questions["preset_name"] == "production":
- check_args += [RUFF_ARGS, MYPY_ARGS]
+ check_args = [BLACK_ARGS, RUFF_ARGS, MYPY_ARGS]
for check_arg in check_args:
result = subprocess.run(
@@ -182,6 +176,12 @@ def get_questions_from_copier_yaml(
"use_python_pip_audit",
"use_dispenser",
"use_pre_commit",
+ "python_linter",
+ "use_python_black",
+ "use_python_mypy",
+ "use_python_pytest",
+ "use_github_actions",
+ "ide_vscode",
}
ignored_keys.update(DEFAULT_PARAMETERS)
diff --git a/tests_generated/test_default_parameters/.copier-answers.yml b/tests_generated/test_default_parameters/.copier-answers.yml
index ee1eff6..50041f3 100644
--- a/tests_generated/test_default_parameters/.copier-answers.yml
+++ b/tests_generated/test_default_parameters/.copier-answers.yml
@@ -12,8 +12,13 @@ ide_vscode: true
indexer_port: 8980
indexer_server: http://localhost
indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
project_name: test_default_parameters
+python_linter: ruff
+use_dispenser: false
+use_github_actions: true
+use_pre_commit: true
use_python_black: true
+use_python_mypy: true
+use_python_pip_audit: true
use_python_pytest: true
diff --git a/tests_generated/test_default_parameters/.github/workflows/cd.yaml b/tests_generated/test_default_parameters/.github/workflows/cd.yaml
new file mode 100644
index 0000000..3e0fd45
--- /dev/null
+++ b/tests_generated/test_default_parameters/.github/workflows/cd.yaml
@@ -0,0 +1,50 @@
+name: Continuous Delivery of Smart Contract
+
+on:
+ push:
+ branches:
+ - main
+
+concurrency: release
+
+jobs:
+ ci-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
+
+ deploy-testnet:
+ runs-on: 'ubuntu-latest'
+ needs: ci-check
+ environment: Test
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Deploy to testnet
+ run: algokit deploy testnet
+ env:
+ # This is the account that becomes the creator of the contract.
+ # Since we are not using the optional dispenser account (via DISPENSER_MNEMONIC),
+ # it must also be funded with enough Algos to deploy and fund the smart contracts created
+ DEPLOYER_MNEMONIC: ${{ secrets.DEPLOYER_MNEMONIC }}
diff --git a/tests_generated/test_default_parameters/.github/workflows/checks.yaml b/tests_generated/test_default_parameters/.github/workflows/checks.yaml
new file mode 100644
index 0000000..f6d0102
--- /dev/null
+++ b/tests_generated/test_default_parameters/.github/workflows/checks.yaml
@@ -0,0 +1,79 @@
+name: Check code base
+
+on:
+ workflow_call:
+
+jobs:
+ checks:
+ runs-on: 'ubuntu-latest'
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Start LocalNet
+ run: algokit localnet start
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Audit with pip-audit
+ run: |
+ # audit non dev dependencies, no exclusions
+ poetry export --without=dev > requirements.txt && poetry run pip-audit -r requirements.txt
+
+ # audit all dependencies, with exclusions.
+ # If a vulnerability is found in a dev dependency without an available fix,
+ # it can be temporarily ignored by adding --ignore-vuln e.g.
+ # --ignore-vuln "GHSA-hcpj-qp55-gfph" # GitPython vulnerability, dev only dependency
+ poetry run pip-audit
+
+ - name: Check formatting with Black
+ run: |
+ # stop the build if there are files that don't meet formatting requirements
+ poetry run black --check .
+
+ - name: Check linting with Ruff
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ poetry run ruff .
+
+ - name: Check types with mypy
+ run: poetry run mypy
+
+ - name: Run tests
+ shell: bash
+ run: |
+ set -o pipefail
+ poetry run pytest --junitxml=pytest-junit.xml
+
+ - name: Build smart contracts
+ run: poetry run python -m smart_contracts build
+
+ - name: Check output stability of the smart contracts
+ shell: bash
+ run: |
+ # Add untracked files as empty so they come up in diff
+ git add -N ./smart_contracts/artifacts
+ # Error out if there are any changes in teal after generating output
+ git diff --exit-code --minimal ./smart_contracts/artifacts || (echo "::error ::Smart contract artifacts have changed, ensure committed artifacts are up to date" && exit 1);
+
+ - name: Run deployer against LocalNet
+ run: poetry run python -m smart_contracts deploy
diff --git a/tests_generated/test_default_parameters/.github/workflows/pr.yaml b/tests_generated/test_default_parameters/.github/workflows/pr.yaml
new file mode 100644
index 0000000..a80f784
--- /dev/null
+++ b/tests_generated/test_default_parameters/.github/workflows/pr.yaml
@@ -0,0 +1,8 @@
+name: Pull Request validation
+
+on: [pull_request]
+
+jobs:
+ pr-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
diff --git a/tests_generated/test_default_parameters/.pre-commit-config.yaml b/tests_generated/test_default_parameters/.pre-commit-config.yaml
new file mode 100644
index 0000000..93bfff5
--- /dev/null
+++ b/tests_generated/test_default_parameters/.pre-commit-config.yaml
@@ -0,0 +1,38 @@
+repos:
+ - repo: local
+ hooks:
+
+ - id: black
+ name: black
+ description: "Black: The uncompromising Python code formatter"
+ entry: poetry run black
+ language: system
+ minimum_pre_commit_version: 2.9.2
+ require_serial: true
+ types_or: [ python, pyi ]
+
+
+ - id: ruff
+ name: ruff
+ description: "Run 'ruff' for extremely fast Python linting"
+ entry: poetry run ruff
+ language: system
+ types: [ python ]
+ args: [ --fix ]
+ require_serial: false
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '0'
+ files: '^(src|tests)/'
+
+
+ - id: mypy
+ name: mypy
+ description: '`mypy` will check Python types for correctness'
+ entry: poetry run mypy
+ language: system
+ types_or: [ python, pyi ]
+ require_serial: true
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '2.9.2'
+ files: '^(src|tests)/'
+
diff --git a/tests_generated/test_default_parameters/.vscode/extensions.json b/tests_generated/test_default_parameters/.vscode/extensions.json
index 9a7b7f1..36d7c10 100644
--- a/tests_generated/test_default_parameters/.vscode/extensions.json
+++ b/tests_generated/test_default_parameters/.vscode/extensions.json
@@ -1,6 +1,8 @@
{
"recommendations": [
"ms-python.python",
+ "charliermarsh.ruff",
+ "matangover.mypy",
"ms-python.black-formatter",
"tamasfe.even-better-toml",
"editorconfig.editorconfig"
diff --git a/tests_generated/test_default_parameters/.vscode/launch.json b/tests_generated/test_default_parameters/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_default_parameters/.vscode/launch.json
+++ b/tests_generated/test_default_parameters/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_default_parameters/.vscode/settings.json b/tests_generated/test_default_parameters/.vscode/settings.json
index c2cc2b6..0c2dfec 100644
--- a/tests_generated/test_default_parameters/.vscode/settings.json
+++ b/tests_generated/test_default_parameters/.vscode/settings.json
@@ -25,6 +25,23 @@
},
"black-formatter.args": ["--config=pyproject.toml"],
"python.testing.pytestEnabled": true,
+ "ruff.enable": true,
+ "ruff.lint.run": "onSave",
+ "ruff.lint.args": ["--config=pyproject.toml"],
+ "ruff.importStrategy": "fromEnvironment",
+ "ruff.fixAll": true, //lint and fix all files in workspace
+ "ruff.organizeImports": true, //organize imports on save
+ "ruff.codeAction.disableRuleComment": {
+ "enable": true
+ },
+ "ruff.codeAction.fixViolation": {
+ "enable": true
+ },
+ "python.analysis.typeCheckingMode": "off",
+ "mypy.configFile": "pyproject.toml",
+ // set to empty array to use config from project
+ "mypy.targets": [],
+ "mypy.runUsingActiveInterpreter": true,
// On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
// so instead let's set it to RemoteSigned for VS Code terminal
diff --git a/tests_generated/test_default_parameters/.vscode/tasks.json b/tests_generated/test_default_parameters/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_default_parameters/.vscode/tasks.json
+++ b/tests_generated/test_default_parameters/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_default_parameters/README.md b/tests_generated/test_default_parameters/README.md
index 41c3c5f..bdc3aa3 100644
--- a/tests_generated/test_default_parameters/README.md
+++ b/tests_generated/test_default_parameters/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -39,7 +46,46 @@ This project has been generated using AlgoKit. See below for default getting sta
1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
2. Follow step 3 above
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
+> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.### Continuous Integration / Continuous Deployment (CI/CD)
+
+This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI/CD workflows, which are located in the [`.github/workflows`](./.github/workflows) folder.
+
+#### Setting up GitHub for CI/CD workflow and TestNet deployment
+
+ 1. Every time you have a change to your smart contract, and when you first initialize the project you need to [build the contract](#initial-setup) and then commit the `smart_contracts/artifacts` folder so the [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) tests pass
+ 2. Decide what values you want to use for the `allow_update`, `allow_delete` and the `on_schema_break`, `on_update` parameters specified in [`contract.py`](./smart_contracts/hello_world/contract.py).
+ When deploying to LocalNet these values are both set to allow update and replacement of the app for convenience. But for non-LocalNet networks
+ the defaults are more conservative.
+ These default values will allow the smart contract to be deployed initially, but will not allow the app to be updated or deleted if is changed and the build will instead fail.
+ To help you decide it may be helpful to read the [AlgoKit Utils app deployment documentation](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/app-deploy.md) or the [AlgoKit smart contract deployment architecture](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md#upgradeable-and-deletable-contracts).
+ 3. Create a [Github Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#creating-an-environment) named `Test`.
+ Note: If you have a private repository and don't have GitHub Enterprise then Environments won't work and you'll need to convert the GitHub Action to use a different approach. Ignore this step if you picked `Starter` preset.
+ 4. Create or obtain a mnemonic for an Algorand account for use on TestNet to deploy apps, referred to as the `DEPLOYER` account.
+ 5. Store the mnemonic as a [secret](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-secrets) `DEPLOYER_MNEMONIC`
+ in the Test environment created in step 3.
+ 6. The account used to deploy the smart contract will require enough funds to create the app, and also fund it. There are two approaches available here:
+ * Either, ensure the account is funded outside of CI/CD.
+ In Testnet, funds can be obtained by using the [Algorand TestNet dispenser](https://bank.testnet.algorand.network/) and we recommend provisioning 50 ALGOs.
+ * Or, fund the account as part of the CI/CD process by using a `DISPENSER_MNEMONIC` GitHub Environment secret to point to a separate `DISPENSER` account that you maintain ALGOs in (similarly, you need to provision ALGOs into this account using the [TestNet dispenser](https://bank.testnet.algorand.network/)).
+
+#### Continuous Integration
+
+For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions:
+ - Python dependencies are audited using [pip-audit](https://pypi.org/project/pip-audit/)
+ - Code formatting is checked using [Black](https://github.com/psf/black)
+ - Linting is checked using [Ruff](https://github.com/charliermarsh/ruff)
+ - Types are checked using [mypy](https://mypy-lang.org/)
+ - Python tests are executed using [pytest](https://docs.pytest.org/)
+ - Smart contract artifacts are built
+ - Smart contract artifacts are checked for [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md)
+ - Smart contract is deployed to a AlgoKit LocalNet instance
+
+#### Continuous Deployment
+
+For pushes to `main` branch, after the above checks pass, the following deployment actions are performed:
+ - The smart contract(s) are deployed to TestNet using [AlgoNode](https://algonode.io).
+
+> Please note deployment is also performed via `algokit deploy` command which can be invoked both via CI as seen on this project, or locally. For more information on how to use `algokit deploy` please see [AlgoKit documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/deploy.md).
# Tools
@@ -47,11 +93,14 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
+- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
+
+- [mypy](https://mypy-lang.org/): Static type checker.
- [pytest](https://docs.pytest.org/): Automated testing.
- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
+ - [pre-commit](https://pre-commit.com/): A framework for managing and maintaining multi-language pre-commit hooks, to enable pre-commit you need to run `pre-commit install` in the root of the repository. This will install the pre-commit hooks and run them against modified files when committing. If any of the hooks fail, the commit will be aborted. To run the hooks on all files, use `pre-commit run --all-files`.
It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder.
diff --git a/tests_generated/test_default_parameters/pyproject.toml b/tests_generated/test_default_parameters/pyproject.toml
index 8261d5d..54b666d 100644
--- a/tests_generated/test_default_parameters/pyproject.toml
+++ b/tests_generated/test_default_parameters/pyproject.toml
@@ -6,21 +6,45 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
+ruff = "^0.1.6"
+mypy = "*"
pytest = "*"
pytest-cov = "*"
pip-audit = "*"
+pre-commit = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
+[tool.ruff]
+line-length = 120
+select = ["E", "F", "ANN", "UP", "N", "C4", "B", "A", "YTT", "W", "FBT", "Q", "RUF", "I"]
+ignore = [
+ "ANN101", # no type for self
+ "ANN102", # no type for cls
+]
+unfixable = ["B", "RUF"]
+
+[tool.ruff.flake8-annotations]
+allow-star-arg-any = true
+suppress-none-returning = true
[tool.pytest.ini_options]
pythonpath = ["smart_contracts", "tests"]
+
+[tool.mypy]
+files = "smart_contracts/"
+python_version = "3.12"
+check_untyped_defs = true
+warn_redundant_casts = true
+warn_unused_ignores = true
+allow_untyped_defs = false
+strict_equality = true
diff --git a/tests_generated/test_default_parameters/smart_contracts/__main__.py b/tests_generated/test_default_parameters/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_default_parameters/smart_contracts/__main__.py
+++ b/tests_generated/test_default_parameters/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_default_parameters/smart_contracts/config.py b/tests_generated/test_default_parameters/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_default_parameters/smart_contracts/config.py
+++ b/tests_generated/test_default_parameters/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_default_parameters/smart_contracts/hello_world/contract.py b/tests_generated/test_default_parameters/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_default_parameters/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_default_parameters/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_default_parameters/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_default_parameters/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_default_parameters/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_default_parameters/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_default_parameters/smart_contracts/helpers/build.py b/tests_generated/test_default_parameters/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_default_parameters/smart_contracts/helpers/build.py
+++ b/tests_generated/test_default_parameters/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_default_parameters/tests/hello_world_test.py b/tests_generated/test_default_parameters/tests/hello_world_test.py
index 50fd332..f4262b9 100644
--- a/tests_generated/test_default_parameters/tests/hello_world_test.py
+++ b/tests_generated/test_default_parameters/tests/hello_world_test.py
@@ -1,33 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_deployment_language-python/.copier-answers.yml b/tests_generated/test_deployment_language-python/.copier-answers.yml
index 0a599d9..e7d20fa 100644
--- a/tests_generated/test_deployment_language-python/.copier-answers.yml
+++ b/tests_generated/test_deployment_language-python/.copier-answers.yml
@@ -12,8 +12,13 @@ ide_vscode: true
indexer_port: 8980
indexer_server: http://localhost
indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
project_name: test_deployment_language-python
+python_linter: ruff
+use_dispenser: false
+use_github_actions: true
+use_pre_commit: true
use_python_black: true
+use_python_mypy: true
+use_python_pip_audit: true
use_python_pytest: true
diff --git a/tests_generated/test_deployment_language-python/.github/workflows/cd.yaml b/tests_generated/test_deployment_language-python/.github/workflows/cd.yaml
new file mode 100644
index 0000000..3e0fd45
--- /dev/null
+++ b/tests_generated/test_deployment_language-python/.github/workflows/cd.yaml
@@ -0,0 +1,50 @@
+name: Continuous Delivery of Smart Contract
+
+on:
+ push:
+ branches:
+ - main
+
+concurrency: release
+
+jobs:
+ ci-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
+
+ deploy-testnet:
+ runs-on: 'ubuntu-latest'
+ needs: ci-check
+ environment: Test
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Deploy to testnet
+ run: algokit deploy testnet
+ env:
+ # This is the account that becomes the creator of the contract.
+ # Since we are not using the optional dispenser account (via DISPENSER_MNEMONIC),
+ # it must also be funded with enough Algos to deploy and fund the smart contracts created
+ DEPLOYER_MNEMONIC: ${{ secrets.DEPLOYER_MNEMONIC }}
diff --git a/tests_generated/test_deployment_language-python/.github/workflows/checks.yaml b/tests_generated/test_deployment_language-python/.github/workflows/checks.yaml
new file mode 100644
index 0000000..f6d0102
--- /dev/null
+++ b/tests_generated/test_deployment_language-python/.github/workflows/checks.yaml
@@ -0,0 +1,79 @@
+name: Check code base
+
+on:
+ workflow_call:
+
+jobs:
+ checks:
+ runs-on: 'ubuntu-latest'
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Start LocalNet
+ run: algokit localnet start
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Audit with pip-audit
+ run: |
+ # audit non dev dependencies, no exclusions
+ poetry export --without=dev > requirements.txt && poetry run pip-audit -r requirements.txt
+
+ # audit all dependencies, with exclusions.
+ # If a vulnerability is found in a dev dependency without an available fix,
+ # it can be temporarily ignored by adding --ignore-vuln e.g.
+ # --ignore-vuln "GHSA-hcpj-qp55-gfph" # GitPython vulnerability, dev only dependency
+ poetry run pip-audit
+
+ - name: Check formatting with Black
+ run: |
+ # stop the build if there are files that don't meet formatting requirements
+ poetry run black --check .
+
+ - name: Check linting with Ruff
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ poetry run ruff .
+
+ - name: Check types with mypy
+ run: poetry run mypy
+
+ - name: Run tests
+ shell: bash
+ run: |
+ set -o pipefail
+ poetry run pytest --junitxml=pytest-junit.xml
+
+ - name: Build smart contracts
+ run: poetry run python -m smart_contracts build
+
+ - name: Check output stability of the smart contracts
+ shell: bash
+ run: |
+ # Add untracked files as empty so they come up in diff
+ git add -N ./smart_contracts/artifacts
+ # Error out if there are any changes in teal after generating output
+ git diff --exit-code --minimal ./smart_contracts/artifacts || (echo "::error ::Smart contract artifacts have changed, ensure committed artifacts are up to date" && exit 1);
+
+ - name: Run deployer against LocalNet
+ run: poetry run python -m smart_contracts deploy
diff --git a/tests_generated/test_deployment_language-python/.github/workflows/pr.yaml b/tests_generated/test_deployment_language-python/.github/workflows/pr.yaml
new file mode 100644
index 0000000..a80f784
--- /dev/null
+++ b/tests_generated/test_deployment_language-python/.github/workflows/pr.yaml
@@ -0,0 +1,8 @@
+name: Pull Request validation
+
+on: [pull_request]
+
+jobs:
+ pr-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
diff --git a/tests_generated/test_deployment_language-python/.pre-commit-config.yaml b/tests_generated/test_deployment_language-python/.pre-commit-config.yaml
new file mode 100644
index 0000000..93bfff5
--- /dev/null
+++ b/tests_generated/test_deployment_language-python/.pre-commit-config.yaml
@@ -0,0 +1,38 @@
+repos:
+ - repo: local
+ hooks:
+
+ - id: black
+ name: black
+ description: "Black: The uncompromising Python code formatter"
+ entry: poetry run black
+ language: system
+ minimum_pre_commit_version: 2.9.2
+ require_serial: true
+ types_or: [ python, pyi ]
+
+
+ - id: ruff
+ name: ruff
+ description: "Run 'ruff' for extremely fast Python linting"
+ entry: poetry run ruff
+ language: system
+ types: [ python ]
+ args: [ --fix ]
+ require_serial: false
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '0'
+ files: '^(src|tests)/'
+
+
+ - id: mypy
+ name: mypy
+ description: '`mypy` will check Python types for correctness'
+ entry: poetry run mypy
+ language: system
+ types_or: [ python, pyi ]
+ require_serial: true
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '2.9.2'
+ files: '^(src|tests)/'
+
diff --git a/tests_generated/test_deployment_language-python/.vscode/extensions.json b/tests_generated/test_deployment_language-python/.vscode/extensions.json
index 9a7b7f1..36d7c10 100644
--- a/tests_generated/test_deployment_language-python/.vscode/extensions.json
+++ b/tests_generated/test_deployment_language-python/.vscode/extensions.json
@@ -1,6 +1,8 @@
{
"recommendations": [
"ms-python.python",
+ "charliermarsh.ruff",
+ "matangover.mypy",
"ms-python.black-formatter",
"tamasfe.even-better-toml",
"editorconfig.editorconfig"
diff --git a/tests_generated/test_deployment_language-python/.vscode/launch.json b/tests_generated/test_deployment_language-python/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_deployment_language-python/.vscode/launch.json
+++ b/tests_generated/test_deployment_language-python/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_deployment_language-python/.vscode/settings.json b/tests_generated/test_deployment_language-python/.vscode/settings.json
index c2cc2b6..0c2dfec 100644
--- a/tests_generated/test_deployment_language-python/.vscode/settings.json
+++ b/tests_generated/test_deployment_language-python/.vscode/settings.json
@@ -25,6 +25,23 @@
},
"black-formatter.args": ["--config=pyproject.toml"],
"python.testing.pytestEnabled": true,
+ "ruff.enable": true,
+ "ruff.lint.run": "onSave",
+ "ruff.lint.args": ["--config=pyproject.toml"],
+ "ruff.importStrategy": "fromEnvironment",
+ "ruff.fixAll": true, //lint and fix all files in workspace
+ "ruff.organizeImports": true, //organize imports on save
+ "ruff.codeAction.disableRuleComment": {
+ "enable": true
+ },
+ "ruff.codeAction.fixViolation": {
+ "enable": true
+ },
+ "python.analysis.typeCheckingMode": "off",
+ "mypy.configFile": "pyproject.toml",
+ // set to empty array to use config from project
+ "mypy.targets": [],
+ "mypy.runUsingActiveInterpreter": true,
// On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
// so instead let's set it to RemoteSigned for VS Code terminal
diff --git a/tests_generated/test_deployment_language-python/.vscode/tasks.json b/tests_generated/test_deployment_language-python/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_deployment_language-python/.vscode/tasks.json
+++ b/tests_generated/test_deployment_language-python/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_deployment_language-python/README.md b/tests_generated/test_deployment_language-python/README.md
index 0f4a114..04790de 100644
--- a/tests_generated/test_deployment_language-python/README.md
+++ b/tests_generated/test_deployment_language-python/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -39,7 +46,46 @@ This project has been generated using AlgoKit. See below for default getting sta
1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
2. Follow step 3 above
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
+> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.### Continuous Integration / Continuous Deployment (CI/CD)
+
+This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI/CD workflows, which are located in the [`.github/workflows`](./.github/workflows) folder.
+
+#### Setting up GitHub for CI/CD workflow and TestNet deployment
+
+ 1. Every time you have a change to your smart contract, and when you first initialize the project you need to [build the contract](#initial-setup) and then commit the `smart_contracts/artifacts` folder so the [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) tests pass
+ 2. Decide what values you want to use for the `allow_update`, `allow_delete` and the `on_schema_break`, `on_update` parameters specified in [`contract.py`](./smart_contracts/hello_world/contract.py).
+ When deploying to LocalNet these values are both set to allow update and replacement of the app for convenience. But for non-LocalNet networks
+ the defaults are more conservative.
+ These default values will allow the smart contract to be deployed initially, but will not allow the app to be updated or deleted if is changed and the build will instead fail.
+ To help you decide it may be helpful to read the [AlgoKit Utils app deployment documentation](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/app-deploy.md) or the [AlgoKit smart contract deployment architecture](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md#upgradeable-and-deletable-contracts).
+ 3. Create a [Github Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#creating-an-environment) named `Test`.
+ Note: If you have a private repository and don't have GitHub Enterprise then Environments won't work and you'll need to convert the GitHub Action to use a different approach. Ignore this step if you picked `Starter` preset.
+ 4. Create or obtain a mnemonic for an Algorand account for use on TestNet to deploy apps, referred to as the `DEPLOYER` account.
+ 5. Store the mnemonic as a [secret](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-secrets) `DEPLOYER_MNEMONIC`
+ in the Test environment created in step 3.
+ 6. The account used to deploy the smart contract will require enough funds to create the app, and also fund it. There are two approaches available here:
+ * Either, ensure the account is funded outside of CI/CD.
+ In Testnet, funds can be obtained by using the [Algorand TestNet dispenser](https://bank.testnet.algorand.network/) and we recommend provisioning 50 ALGOs.
+ * Or, fund the account as part of the CI/CD process by using a `DISPENSER_MNEMONIC` GitHub Environment secret to point to a separate `DISPENSER` account that you maintain ALGOs in (similarly, you need to provision ALGOs into this account using the [TestNet dispenser](https://bank.testnet.algorand.network/)).
+
+#### Continuous Integration
+
+For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions:
+ - Python dependencies are audited using [pip-audit](https://pypi.org/project/pip-audit/)
+ - Code formatting is checked using [Black](https://github.com/psf/black)
+ - Linting is checked using [Ruff](https://github.com/charliermarsh/ruff)
+ - Types are checked using [mypy](https://mypy-lang.org/)
+ - Python tests are executed using [pytest](https://docs.pytest.org/)
+ - Smart contract artifacts are built
+ - Smart contract artifacts are checked for [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md)
+ - Smart contract is deployed to a AlgoKit LocalNet instance
+
+#### Continuous Deployment
+
+For pushes to `main` branch, after the above checks pass, the following deployment actions are performed:
+ - The smart contract(s) are deployed to TestNet using [AlgoNode](https://algonode.io).
+
+> Please note deployment is also performed via `algokit deploy` command which can be invoked both via CI as seen on this project, or locally. For more information on how to use `algokit deploy` please see [AlgoKit documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/deploy.md).
# Tools
@@ -47,11 +93,14 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
+- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
+
+- [mypy](https://mypy-lang.org/): Static type checker.
- [pytest](https://docs.pytest.org/): Automated testing.
- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
+ - [pre-commit](https://pre-commit.com/): A framework for managing and maintaining multi-language pre-commit hooks, to enable pre-commit you need to run `pre-commit install` in the root of the repository. This will install the pre-commit hooks and run them against modified files when committing. If any of the hooks fail, the commit will be aborted. To run the hooks on all files, use `pre-commit run --all-files`.
It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder.
diff --git a/tests_generated/test_deployment_language-python/pyproject.toml b/tests_generated/test_deployment_language-python/pyproject.toml
index 213a92b..3605b74 100644
--- a/tests_generated/test_deployment_language-python/pyproject.toml
+++ b/tests_generated/test_deployment_language-python/pyproject.toml
@@ -6,21 +6,45 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
+ruff = "^0.1.6"
+mypy = "*"
pytest = "*"
pytest-cov = "*"
pip-audit = "*"
+pre-commit = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
+[tool.ruff]
+line-length = 120
+select = ["E", "F", "ANN", "UP", "N", "C4", "B", "A", "YTT", "W", "FBT", "Q", "RUF", "I"]
+ignore = [
+ "ANN101", # no type for self
+ "ANN102", # no type for cls
+]
+unfixable = ["B", "RUF"]
+
+[tool.ruff.flake8-annotations]
+allow-star-arg-any = true
+suppress-none-returning = true
[tool.pytest.ini_options]
pythonpath = ["smart_contracts", "tests"]
+
+[tool.mypy]
+files = "smart_contracts/"
+python_version = "3.12"
+check_untyped_defs = true
+warn_redundant_casts = true
+warn_unused_ignores = true
+allow_untyped_defs = false
+strict_equality = true
diff --git a/tests_generated/test_deployment_language-python/smart_contracts/__main__.py b/tests_generated/test_deployment_language-python/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_deployment_language-python/smart_contracts/__main__.py
+++ b/tests_generated/test_deployment_language-python/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_deployment_language-python/smart_contracts/config.py b/tests_generated/test_deployment_language-python/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_deployment_language-python/smart_contracts/config.py
+++ b/tests_generated/test_deployment_language-python/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_deployment_language-python/smart_contracts/hello_world/contract.py b/tests_generated/test_deployment_language-python/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_deployment_language-python/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_deployment_language-python/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_deployment_language-python/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_deployment_language-python/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_deployment_language-python/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_deployment_language-python/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_deployment_language-python/smart_contracts/helpers/build.py b/tests_generated/test_deployment_language-python/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_deployment_language-python/smart_contracts/helpers/build.py
+++ b/tests_generated/test_deployment_language-python/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_deployment_language-python/tests/hello_world_test.py b/tests_generated/test_deployment_language-python/tests/hello_world_test.py
index 50fd332..f4262b9 100644
--- a/tests_generated/test_deployment_language-python/tests/hello_world_test.py
+++ b/tests_generated/test_deployment_language-python/tests/hello_world_test.py
@@ -1,33 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_deployment_language-typescript/.copier-answers.yml b/tests_generated/test_deployment_language-typescript/.copier-answers.yml
index 7e61565..53b370a 100644
--- a/tests_generated/test_deployment_language-typescript/.copier-answers.yml
+++ b/tests_generated/test_deployment_language-typescript/.copier-answers.yml
@@ -12,8 +12,13 @@ ide_vscode: true
indexer_port: 8980
indexer_server: http://localhost
indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
project_name: test_deployment_language-typescript
+python_linter: ruff
+use_dispenser: false
+use_github_actions: true
+use_pre_commit: true
use_python_black: true
+use_python_mypy: true
+use_python_pip_audit: true
use_python_pytest: true
diff --git a/tests_generated/test_deployment_language-typescript/.github/workflows/cd.yaml b/tests_generated/test_deployment_language-typescript/.github/workflows/cd.yaml
new file mode 100644
index 0000000..3e0fd45
--- /dev/null
+++ b/tests_generated/test_deployment_language-typescript/.github/workflows/cd.yaml
@@ -0,0 +1,50 @@
+name: Continuous Delivery of Smart Contract
+
+on:
+ push:
+ branches:
+ - main
+
+concurrency: release
+
+jobs:
+ ci-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
+
+ deploy-testnet:
+ runs-on: 'ubuntu-latest'
+ needs: ci-check
+ environment: Test
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Deploy to testnet
+ run: algokit deploy testnet
+ env:
+ # This is the account that becomes the creator of the contract.
+ # Since we are not using the optional dispenser account (via DISPENSER_MNEMONIC),
+ # it must also be funded with enough Algos to deploy and fund the smart contracts created
+ DEPLOYER_MNEMONIC: ${{ secrets.DEPLOYER_MNEMONIC }}
diff --git a/tests_generated/test_deployment_language-typescript/.github/workflows/checks.yaml b/tests_generated/test_deployment_language-typescript/.github/workflows/checks.yaml
new file mode 100644
index 0000000..eea57bf
--- /dev/null
+++ b/tests_generated/test_deployment_language-typescript/.github/workflows/checks.yaml
@@ -0,0 +1,79 @@
+name: Check code base
+
+on:
+ workflow_call:
+
+jobs:
+ checks:
+ runs-on: 'ubuntu-latest'
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Start LocalNet
+ run: algokit localnet start
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Audit with pip-audit
+ run: |
+ # audit non dev dependencies, no exclusions
+ poetry export --without=dev > requirements.txt && poetry run pip-audit -r requirements.txt
+
+ # audit all dependencies, with exclusions.
+ # If a vulnerability is found in a dev dependency without an available fix,
+ # it can be temporarily ignored by adding --ignore-vuln e.g.
+ # --ignore-vuln "GHSA-hcpj-qp55-gfph" # GitPython vulnerability, dev only dependency
+ poetry run pip-audit
+
+ - name: Check formatting with Black
+ run: |
+ # stop the build if there are files that don't meet formatting requirements
+ poetry run black --check .
+
+ - name: Check linting with Ruff
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ poetry run ruff .
+
+ - name: Check types with mypy
+ run: poetry run mypy
+
+ - name: Run tests
+ shell: bash
+ run: |
+ set -o pipefail
+ poetry run pytest --junitxml=pytest-junit.xml
+
+ - name: Build smart contracts
+ run: poetry run python -m smart_contracts build
+
+ - name: Check output stability of the smart contracts
+ shell: bash
+ run: |
+ # Add untracked files as empty so they come up in diff
+ git add -N ./smart_contracts/artifacts
+ # Error out if there are any changes in teal after generating output
+ git diff --exit-code --minimal ./smart_contracts/artifacts || (echo "::error ::Smart contract artifacts have changed, ensure committed artifacts are up to date" && exit 1);
+
+ - name: Run deployer against LocalNet
+ run: npm run --prefix smart_contracts deploy:ci
diff --git a/tests_generated/test_deployment_language-typescript/.github/workflows/pr.yaml b/tests_generated/test_deployment_language-typescript/.github/workflows/pr.yaml
new file mode 100644
index 0000000..a80f784
--- /dev/null
+++ b/tests_generated/test_deployment_language-typescript/.github/workflows/pr.yaml
@@ -0,0 +1,8 @@
+name: Pull Request validation
+
+on: [pull_request]
+
+jobs:
+ pr-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
diff --git a/tests_generated/test_deployment_language-typescript/.pre-commit-config.yaml b/tests_generated/test_deployment_language-typescript/.pre-commit-config.yaml
new file mode 100644
index 0000000..93bfff5
--- /dev/null
+++ b/tests_generated/test_deployment_language-typescript/.pre-commit-config.yaml
@@ -0,0 +1,38 @@
+repos:
+ - repo: local
+ hooks:
+
+ - id: black
+ name: black
+ description: "Black: The uncompromising Python code formatter"
+ entry: poetry run black
+ language: system
+ minimum_pre_commit_version: 2.9.2
+ require_serial: true
+ types_or: [ python, pyi ]
+
+
+ - id: ruff
+ name: ruff
+ description: "Run 'ruff' for extremely fast Python linting"
+ entry: poetry run ruff
+ language: system
+ types: [ python ]
+ args: [ --fix ]
+ require_serial: false
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '0'
+ files: '^(src|tests)/'
+
+
+ - id: mypy
+ name: mypy
+ description: '`mypy` will check Python types for correctness'
+ entry: poetry run mypy
+ language: system
+ types_or: [ python, pyi ]
+ require_serial: true
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '2.9.2'
+ files: '^(src|tests)/'
+
diff --git a/tests_generated/test_deployment_language-typescript/.vscode/extensions.json b/tests_generated/test_deployment_language-typescript/.vscode/extensions.json
index 5ed3b87..c170e6c 100644
--- a/tests_generated/test_deployment_language-typescript/.vscode/extensions.json
+++ b/tests_generated/test_deployment_language-typescript/.vscode/extensions.json
@@ -1,6 +1,8 @@
{
"recommendations": [
"ms-python.python",
+ "charliermarsh.ruff",
+ "matangover.mypy",
"ms-python.black-formatter",
"esbenp.prettier-vscode",
"tamasfe.even-better-toml",
diff --git a/tests_generated/test_deployment_language-typescript/.vscode/launch.json b/tests_generated/test_deployment_language-typescript/.vscode/launch.json
index 4ccd8e1..b5c1fb6 100644
--- a/tests_generated/test_deployment_language-typescript/.vscode/launch.json
+++ b/tests_generated/test_deployment_language-typescript/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
@@ -10,11 +10,11 @@
"cwd": "${workspaceFolder}/smart_contracts",
"console": "integratedTerminal",
"skipFiles": ["/**", "node_modules/**"],
- "preLaunchTask": "Build Beaker application (+ LocalNet)",
+ "preLaunchTask": "Build Puya application (+ LocalNet)",
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
@@ -25,7 +25,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_deployment_language-typescript/.vscode/settings.json b/tests_generated/test_deployment_language-typescript/.vscode/settings.json
index 64ef130..50d7af1 100644
--- a/tests_generated/test_deployment_language-typescript/.vscode/settings.json
+++ b/tests_generated/test_deployment_language-typescript/.vscode/settings.json
@@ -28,6 +28,23 @@
},
"black-formatter.args": ["--config=pyproject.toml"],
"python.testing.pytestEnabled": true,
+ "ruff.enable": true,
+ "ruff.lint.run": "onSave",
+ "ruff.lint.args": ["--config=pyproject.toml"],
+ "ruff.importStrategy": "fromEnvironment",
+ "ruff.fixAll": true, //lint and fix all files in workspace
+ "ruff.organizeImports": true, //organize imports on save
+ "ruff.codeAction.disableRuleComment": {
+ "enable": true
+ },
+ "ruff.codeAction.fixViolation": {
+ "enable": true
+ },
+ "python.analysis.typeCheckingMode": "off",
+ "mypy.configFile": "pyproject.toml",
+ // set to empty array to use config from project
+ "mypy.targets": [],
+ "mypy.runUsingActiveInterpreter": true,
// On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
// so instead let's set it to RemoteSigned for VS Code terminal
diff --git a/tests_generated/test_deployment_language-typescript/.vscode/tasks.json b/tests_generated/test_deployment_language-typescript/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_deployment_language-typescript/.vscode/tasks.json
+++ b/tests_generated/test_deployment_language-typescript/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_deployment_language-typescript/README.md b/tests_generated/test_deployment_language-typescript/README.md
index 0fd1a49..0c2c878 100644
--- a/tests_generated/test_deployment_language-typescript/README.md
+++ b/tests_generated/test_deployment_language-typescript/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -40,7 +47,46 @@ This project has been generated using AlgoKit. See below for default getting sta
1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
2. Follow step 3 above
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
+> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.### Continuous Integration / Continuous Deployment (CI/CD)
+
+This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI/CD workflows, which are located in the [`.github/workflows`](./.github/workflows) folder.
+
+#### Setting up GitHub for CI/CD workflow and TestNet deployment
+
+ 1. Every time you have a change to your smart contract, and when you first initialize the project you need to [build the contract](#initial-setup) and then commit the `smart_contracts/artifacts` folder so the [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) tests pass
+ 2. Decide what values you want to use for the `allowUpdate` and `allowDelete` parameters specified in [`deploy-config.ts`](./smart_contracts/hello_world/deploy-config.ts).
+ When deploying to LocalNet these values are both set to `true` for convenience. But for non-LocalNet networks
+ they are more conservative and use `false`
+ These default values will allow the smart contract to be deployed initially, but will not allow the app to be updated or deleted if is changed and the build will instead fail.
+ To help you decide it may be helpful to read the [AlgoKit Utils app deployment documentation](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/app-deploy.md) or the [AlgoKit smart contract deployment architecture](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md#upgradeable-and-deletable-contracts).
+ 3. Create a [Github Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#creating-an-environment) named `Test`.
+ Note: If you have a private repository and don't have GitHub Enterprise then Environments won't work and you'll need to convert the GitHub Action to use a different approach. Ignore this step if you picked `Starter` preset.
+ 4. Create or obtain a mnemonic for an Algorand account for use on TestNet to deploy apps, referred to as the `DEPLOYER` account.
+ 5. Store the mnemonic as a [secret](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-secrets) `DEPLOYER_MNEMONIC`
+ in the Test environment created in step 3.
+ 6. The account used to deploy the smart contract will require enough funds to create the app, and also fund it. There are two approaches available here:
+ * Either, ensure the account is funded outside of CI/CD.
+ In Testnet, funds can be obtained by using the [Algorand TestNet dispenser](https://bank.testnet.algorand.network/) and we recommend provisioning 50 ALGOs.
+ * Or, fund the account as part of the CI/CD process by using a `DISPENSER_MNEMONIC` GitHub Environment secret to point to a separate `DISPENSER` account that you maintain ALGOs in (similarly, you need to provision ALGOs into this account using the [TestNet dispenser](https://bank.testnet.algorand.network/)).
+
+#### Continuous Integration
+
+For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions:
+ - Python dependencies are audited using [pip-audit](https://pypi.org/project/pip-audit/)
+ - Code formatting is checked using [Black](https://github.com/psf/black)
+ - Linting is checked using [Ruff](https://github.com/charliermarsh/ruff)
+ - Types are checked using [mypy](https://mypy-lang.org/)
+ - Python tests are executed using [pytest](https://docs.pytest.org/)
+ - Smart contract artifacts are built
+ - Smart contract artifacts are checked for [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md)
+ - Smart contract is deployed to a AlgoKit LocalNet instance
+
+#### Continuous Deployment
+
+For pushes to `main` branch, after the above checks pass, the following deployment actions are performed:
+ - The smart contract(s) are deployed to TestNet using [AlgoNode](https://algonode.io).
+
+> Please note deployment is also performed via `algokit deploy` command which can be invoked both via CI as seen on this project, or locally. For more information on how to use `algokit deploy` please see [AlgoKit documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/deploy.md).
# Tools
@@ -48,12 +94,15 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-ts) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
+- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
+
+- [mypy](https://mypy-lang.org/): Static type checker.
- [pytest](https://docs.pytest.org/): Automated testing.
- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
+ - [pre-commit](https://pre-commit.com/): A framework for managing and maintaining multi-language pre-commit hooks, to enable pre-commit you need to run `pre-commit install` in the root of the repository. This will install the pre-commit hooks and run them against modified files when committing. If any of the hooks fail, the commit will be aborted. To run the hooks on all files, use `pre-commit run --all-files`.
- [npm](https://www.npmjs.com/): Node.js package manager
- [TypeScript](https://www.typescriptlang.org/): Strongly typed programming language that builds on JavaScript
- [ts-node-dev](https://github.com/wclr/ts-node-dev): TypeScript development execution environment
diff --git a/tests_generated/test_deployment_language-typescript/pyproject.toml b/tests_generated/test_deployment_language-typescript/pyproject.toml
index ff6dff4..7668a04 100644
--- a/tests_generated/test_deployment_language-typescript/pyproject.toml
+++ b/tests_generated/test_deployment_language-typescript/pyproject.toml
@@ -6,21 +6,45 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
+ruff = "^0.1.6"
+mypy = "*"
pytest = "*"
pytest-cov = "*"
pip-audit = "*"
+pre-commit = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
+[tool.ruff]
+line-length = 120
+select = ["E", "F", "ANN", "UP", "N", "C4", "B", "A", "YTT", "W", "FBT", "Q", "RUF", "I"]
+ignore = [
+ "ANN101", # no type for self
+ "ANN102", # no type for cls
+]
+unfixable = ["B", "RUF"]
+
+[tool.ruff.flake8-annotations]
+allow-star-arg-any = true
+suppress-none-returning = true
[tool.pytest.ini_options]
pythonpath = ["smart_contracts", "tests"]
+
+[tool.mypy]
+files = "smart_contracts/"
+python_version = "3.12"
+check_untyped_defs = true
+warn_redundant_casts = true
+warn_unused_ignores = true
+allow_untyped_defs = false
+strict_equality = true
diff --git a/tests_generated/test_deployment_language-typescript/smart_contracts/__main__.py b/tests_generated/test_deployment_language-typescript/smart_contracts/__main__.py
index 0026e40..b91ab2e 100644
--- a/tests_generated/test_deployment_language-typescript/smart_contracts/__main__.py
+++ b/tests_generated/test_deployment_language-typescript/smart_contracts/__main__.py
@@ -21,8 +21,8 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
if __name__ == "__main__":
diff --git a/tests_generated/test_deployment_language-typescript/smart_contracts/config.py b/tests_generated/test_deployment_language-typescript/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_deployment_language-typescript/smart_contracts/config.py
+++ b/tests_generated/test_deployment_language-typescript/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_deployment_language-typescript/smart_contracts/hello_world/contract.py b/tests_generated/test_deployment_language-typescript/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_deployment_language-typescript/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_deployment_language-typescript/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_deployment_language-typescript/smart_contracts/hello_world/deploy-config.ts b/tests_generated/test_deployment_language-typescript/smart_contracts/hello_world/deploy-config.ts
index 527fe2c..c8b69ba 100644
--- a/tests_generated/test_deployment_language-typescript/smart_contracts/hello_world/deploy-config.ts
+++ b/tests_generated/test_deployment_language-typescript/smart_contracts/hello_world/deploy-config.ts
@@ -25,11 +25,12 @@ export async function deploy() {
},
algod,
)
+
const app = await appClient.deploy({
onSchemaBreak: 'append',
onUpdate: 'append',
})
-
+
// If app was just created fund the app account
if (['create', 'replace'].includes(app.operationPerformed)) {
diff --git a/tests_generated/test_deployment_language-typescript/smart_contracts/helpers/build.py b/tests_generated/test_deployment_language-typescript/smart_contracts/helpers/build.py
index 20d6d6d..67377d3 100644
--- a/tests_generated/test_deployment_language-typescript/smart_contracts/helpers/build.py
+++ b/tests_generated/test_deployment_language-typescript/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "ts"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_deployment_language-typescript/tests/hello_world_test.py b/tests_generated/test_deployment_language-typescript/tests/hello_world_test.py
index 50fd332..f4262b9 100644
--- a/tests_generated/test_deployment_language-typescript/tests/hello_world_test.py
+++ b/tests_generated/test_deployment_language-typescript/tests/hello_world_test.py
@@ -1,33 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_ide_jetbrains-False/.copier-answers.yml b/tests_generated/test_ide_jetbrains-False/.copier-answers.yml
index 325f797..708300a 100644
--- a/tests_generated/test_ide_jetbrains-False/.copier-answers.yml
+++ b/tests_generated/test_ide_jetbrains-False/.copier-answers.yml
@@ -12,8 +12,13 @@ ide_vscode: true
indexer_port: 8980
indexer_server: http://localhost
indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
project_name: test_ide_jetbrains-False
+python_linter: ruff
+use_dispenser: false
+use_github_actions: true
+use_pre_commit: true
use_python_black: true
+use_python_mypy: true
+use_python_pip_audit: true
use_python_pytest: true
diff --git a/tests_generated/test_ide_jetbrains-False/.github/workflows/cd.yaml b/tests_generated/test_ide_jetbrains-False/.github/workflows/cd.yaml
new file mode 100644
index 0000000..3e0fd45
--- /dev/null
+++ b/tests_generated/test_ide_jetbrains-False/.github/workflows/cd.yaml
@@ -0,0 +1,50 @@
+name: Continuous Delivery of Smart Contract
+
+on:
+ push:
+ branches:
+ - main
+
+concurrency: release
+
+jobs:
+ ci-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
+
+ deploy-testnet:
+ runs-on: 'ubuntu-latest'
+ needs: ci-check
+ environment: Test
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Deploy to testnet
+ run: algokit deploy testnet
+ env:
+ # This is the account that becomes the creator of the contract.
+ # Since we are not using the optional dispenser account (via DISPENSER_MNEMONIC),
+ # it must also be funded with enough Algos to deploy and fund the smart contracts created
+ DEPLOYER_MNEMONIC: ${{ secrets.DEPLOYER_MNEMONIC }}
diff --git a/tests_generated/test_ide_jetbrains-False/.github/workflows/checks.yaml b/tests_generated/test_ide_jetbrains-False/.github/workflows/checks.yaml
new file mode 100644
index 0000000..f6d0102
--- /dev/null
+++ b/tests_generated/test_ide_jetbrains-False/.github/workflows/checks.yaml
@@ -0,0 +1,79 @@
+name: Check code base
+
+on:
+ workflow_call:
+
+jobs:
+ checks:
+ runs-on: 'ubuntu-latest'
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Start LocalNet
+ run: algokit localnet start
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Audit with pip-audit
+ run: |
+ # audit non dev dependencies, no exclusions
+ poetry export --without=dev > requirements.txt && poetry run pip-audit -r requirements.txt
+
+ # audit all dependencies, with exclusions.
+ # If a vulnerability is found in a dev dependency without an available fix,
+ # it can be temporarily ignored by adding --ignore-vuln e.g.
+ # --ignore-vuln "GHSA-hcpj-qp55-gfph" # GitPython vulnerability, dev only dependency
+ poetry run pip-audit
+
+ - name: Check formatting with Black
+ run: |
+ # stop the build if there are files that don't meet formatting requirements
+ poetry run black --check .
+
+ - name: Check linting with Ruff
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ poetry run ruff .
+
+ - name: Check types with mypy
+ run: poetry run mypy
+
+ - name: Run tests
+ shell: bash
+ run: |
+ set -o pipefail
+ poetry run pytest --junitxml=pytest-junit.xml
+
+ - name: Build smart contracts
+ run: poetry run python -m smart_contracts build
+
+ - name: Check output stability of the smart contracts
+ shell: bash
+ run: |
+ # Add untracked files as empty so they come up in diff
+ git add -N ./smart_contracts/artifacts
+ # Error out if there are any changes in teal after generating output
+ git diff --exit-code --minimal ./smart_contracts/artifacts || (echo "::error ::Smart contract artifacts have changed, ensure committed artifacts are up to date" && exit 1);
+
+ - name: Run deployer against LocalNet
+ run: poetry run python -m smart_contracts deploy
diff --git a/tests_generated/test_ide_jetbrains-False/.github/workflows/pr.yaml b/tests_generated/test_ide_jetbrains-False/.github/workflows/pr.yaml
new file mode 100644
index 0000000..a80f784
--- /dev/null
+++ b/tests_generated/test_ide_jetbrains-False/.github/workflows/pr.yaml
@@ -0,0 +1,8 @@
+name: Pull Request validation
+
+on: [pull_request]
+
+jobs:
+ pr-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
diff --git a/tests_generated/test_ide_jetbrains-False/.pre-commit-config.yaml b/tests_generated/test_ide_jetbrains-False/.pre-commit-config.yaml
new file mode 100644
index 0000000..93bfff5
--- /dev/null
+++ b/tests_generated/test_ide_jetbrains-False/.pre-commit-config.yaml
@@ -0,0 +1,38 @@
+repos:
+ - repo: local
+ hooks:
+
+ - id: black
+ name: black
+ description: "Black: The uncompromising Python code formatter"
+ entry: poetry run black
+ language: system
+ minimum_pre_commit_version: 2.9.2
+ require_serial: true
+ types_or: [ python, pyi ]
+
+
+ - id: ruff
+ name: ruff
+ description: "Run 'ruff' for extremely fast Python linting"
+ entry: poetry run ruff
+ language: system
+ types: [ python ]
+ args: [ --fix ]
+ require_serial: false
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '0'
+ files: '^(src|tests)/'
+
+
+ - id: mypy
+ name: mypy
+ description: '`mypy` will check Python types for correctness'
+ entry: poetry run mypy
+ language: system
+ types_or: [ python, pyi ]
+ require_serial: true
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '2.9.2'
+ files: '^(src|tests)/'
+
diff --git a/tests_generated/test_ide_jetbrains-False/.vscode/extensions.json b/tests_generated/test_ide_jetbrains-False/.vscode/extensions.json
index 9a7b7f1..36d7c10 100644
--- a/tests_generated/test_ide_jetbrains-False/.vscode/extensions.json
+++ b/tests_generated/test_ide_jetbrains-False/.vscode/extensions.json
@@ -1,6 +1,8 @@
{
"recommendations": [
"ms-python.python",
+ "charliermarsh.ruff",
+ "matangover.mypy",
"ms-python.black-formatter",
"tamasfe.even-better-toml",
"editorconfig.editorconfig"
diff --git a/tests_generated/test_ide_jetbrains-False/.vscode/launch.json b/tests_generated/test_ide_jetbrains-False/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_ide_jetbrains-False/.vscode/launch.json
+++ b/tests_generated/test_ide_jetbrains-False/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_ide_jetbrains-False/.vscode/settings.json b/tests_generated/test_ide_jetbrains-False/.vscode/settings.json
index c2cc2b6..0c2dfec 100644
--- a/tests_generated/test_ide_jetbrains-False/.vscode/settings.json
+++ b/tests_generated/test_ide_jetbrains-False/.vscode/settings.json
@@ -25,6 +25,23 @@
},
"black-formatter.args": ["--config=pyproject.toml"],
"python.testing.pytestEnabled": true,
+ "ruff.enable": true,
+ "ruff.lint.run": "onSave",
+ "ruff.lint.args": ["--config=pyproject.toml"],
+ "ruff.importStrategy": "fromEnvironment",
+ "ruff.fixAll": true, //lint and fix all files in workspace
+ "ruff.organizeImports": true, //organize imports on save
+ "ruff.codeAction.disableRuleComment": {
+ "enable": true
+ },
+ "ruff.codeAction.fixViolation": {
+ "enable": true
+ },
+ "python.analysis.typeCheckingMode": "off",
+ "mypy.configFile": "pyproject.toml",
+ // set to empty array to use config from project
+ "mypy.targets": [],
+ "mypy.runUsingActiveInterpreter": true,
// On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
// so instead let's set it to RemoteSigned for VS Code terminal
diff --git a/tests_generated/test_ide_jetbrains-False/.vscode/tasks.json b/tests_generated/test_ide_jetbrains-False/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_ide_jetbrains-False/.vscode/tasks.json
+++ b/tests_generated/test_ide_jetbrains-False/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_ide_jetbrains-False/README.md b/tests_generated/test_ide_jetbrains-False/README.md
index 45f616b..44d72ed 100644
--- a/tests_generated/test_ide_jetbrains-False/README.md
+++ b/tests_generated/test_ide_jetbrains-False/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -39,7 +46,46 @@ This project has been generated using AlgoKit. See below for default getting sta
1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
2. Follow step 3 above
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
+> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.### Continuous Integration / Continuous Deployment (CI/CD)
+
+This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI/CD workflows, which are located in the [`.github/workflows`](./.github/workflows) folder.
+
+#### Setting up GitHub for CI/CD workflow and TestNet deployment
+
+ 1. Every time you have a change to your smart contract, and when you first initialize the project you need to [build the contract](#initial-setup) and then commit the `smart_contracts/artifacts` folder so the [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) tests pass
+ 2. Decide what values you want to use for the `allow_update`, `allow_delete` and the `on_schema_break`, `on_update` parameters specified in [`contract.py`](./smart_contracts/hello_world/contract.py).
+ When deploying to LocalNet these values are both set to allow update and replacement of the app for convenience. But for non-LocalNet networks
+ the defaults are more conservative.
+ These default values will allow the smart contract to be deployed initially, but will not allow the app to be updated or deleted if is changed and the build will instead fail.
+ To help you decide it may be helpful to read the [AlgoKit Utils app deployment documentation](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/app-deploy.md) or the [AlgoKit smart contract deployment architecture](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md#upgradeable-and-deletable-contracts).
+ 3. Create a [Github Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#creating-an-environment) named `Test`.
+ Note: If you have a private repository and don't have GitHub Enterprise then Environments won't work and you'll need to convert the GitHub Action to use a different approach. Ignore this step if you picked `Starter` preset.
+ 4. Create or obtain a mnemonic for an Algorand account for use on TestNet to deploy apps, referred to as the `DEPLOYER` account.
+ 5. Store the mnemonic as a [secret](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-secrets) `DEPLOYER_MNEMONIC`
+ in the Test environment created in step 3.
+ 6. The account used to deploy the smart contract will require enough funds to create the app, and also fund it. There are two approaches available here:
+ * Either, ensure the account is funded outside of CI/CD.
+ In Testnet, funds can be obtained by using the [Algorand TestNet dispenser](https://bank.testnet.algorand.network/) and we recommend provisioning 50 ALGOs.
+ * Or, fund the account as part of the CI/CD process by using a `DISPENSER_MNEMONIC` GitHub Environment secret to point to a separate `DISPENSER` account that you maintain ALGOs in (similarly, you need to provision ALGOs into this account using the [TestNet dispenser](https://bank.testnet.algorand.network/)).
+
+#### Continuous Integration
+
+For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions:
+ - Python dependencies are audited using [pip-audit](https://pypi.org/project/pip-audit/)
+ - Code formatting is checked using [Black](https://github.com/psf/black)
+ - Linting is checked using [Ruff](https://github.com/charliermarsh/ruff)
+ - Types are checked using [mypy](https://mypy-lang.org/)
+ - Python tests are executed using [pytest](https://docs.pytest.org/)
+ - Smart contract artifacts are built
+ - Smart contract artifacts are checked for [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md)
+ - Smart contract is deployed to a AlgoKit LocalNet instance
+
+#### Continuous Deployment
+
+For pushes to `main` branch, after the above checks pass, the following deployment actions are performed:
+ - The smart contract(s) are deployed to TestNet using [AlgoNode](https://algonode.io).
+
+> Please note deployment is also performed via `algokit deploy` command which can be invoked both via CI as seen on this project, or locally. For more information on how to use `algokit deploy` please see [AlgoKit documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/deploy.md).
# Tools
@@ -47,11 +93,14 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
+- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
+
+- [mypy](https://mypy-lang.org/): Static type checker.
- [pytest](https://docs.pytest.org/): Automated testing.
- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
+ - [pre-commit](https://pre-commit.com/): A framework for managing and maintaining multi-language pre-commit hooks, to enable pre-commit you need to run `pre-commit install` in the root of the repository. This will install the pre-commit hooks and run them against modified files when committing. If any of the hooks fail, the commit will be aborted. To run the hooks on all files, use `pre-commit run --all-files`.
It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder.
diff --git a/tests_generated/test_ide_jetbrains-False/pyproject.toml b/tests_generated/test_ide_jetbrains-False/pyproject.toml
index b7550c0..c89bafd 100644
--- a/tests_generated/test_ide_jetbrains-False/pyproject.toml
+++ b/tests_generated/test_ide_jetbrains-False/pyproject.toml
@@ -6,21 +6,45 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
+ruff = "^0.1.6"
+mypy = "*"
pytest = "*"
pytest-cov = "*"
pip-audit = "*"
+pre-commit = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
+[tool.ruff]
+line-length = 120
+select = ["E", "F", "ANN", "UP", "N", "C4", "B", "A", "YTT", "W", "FBT", "Q", "RUF", "I"]
+ignore = [
+ "ANN101", # no type for self
+ "ANN102", # no type for cls
+]
+unfixable = ["B", "RUF"]
+
+[tool.ruff.flake8-annotations]
+allow-star-arg-any = true
+suppress-none-returning = true
[tool.pytest.ini_options]
pythonpath = ["smart_contracts", "tests"]
+
+[tool.mypy]
+files = "smart_contracts/"
+python_version = "3.12"
+check_untyped_defs = true
+warn_redundant_casts = true
+warn_unused_ignores = true
+allow_untyped_defs = false
+strict_equality = true
diff --git a/tests_generated/test_ide_jetbrains-False/smart_contracts/__main__.py b/tests_generated/test_ide_jetbrains-False/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_ide_jetbrains-False/smart_contracts/__main__.py
+++ b/tests_generated/test_ide_jetbrains-False/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_ide_jetbrains-False/smart_contracts/config.py b/tests_generated/test_ide_jetbrains-False/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_ide_jetbrains-False/smart_contracts/config.py
+++ b/tests_generated/test_ide_jetbrains-False/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_ide_jetbrains-False/smart_contracts/hello_world/contract.py b/tests_generated/test_ide_jetbrains-False/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_ide_jetbrains-False/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_ide_jetbrains-False/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_ide_jetbrains-False/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_ide_jetbrains-False/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_ide_jetbrains-False/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_ide_jetbrains-False/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_ide_jetbrains-False/smart_contracts/helpers/build.py b/tests_generated/test_ide_jetbrains-False/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_ide_jetbrains-False/smart_contracts/helpers/build.py
+++ b/tests_generated/test_ide_jetbrains-False/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_ide_jetbrains-False/tests/hello_world_test.py b/tests_generated/test_ide_jetbrains-False/tests/hello_world_test.py
index 50fd332..f4262b9 100644
--- a/tests_generated/test_ide_jetbrains-False/tests/hello_world_test.py
+++ b/tests_generated/test_ide_jetbrains-False/tests/hello_world_test.py
@@ -1,33 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_ide_jetbrains-True/.copier-answers.yml b/tests_generated/test_ide_jetbrains-True/.copier-answers.yml
index 851e711..f318a4d 100644
--- a/tests_generated/test_ide_jetbrains-True/.copier-answers.yml
+++ b/tests_generated/test_ide_jetbrains-True/.copier-answers.yml
@@ -12,8 +12,13 @@ ide_vscode: true
indexer_port: 8980
indexer_server: http://localhost
indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
project_name: test_ide_jetbrains-True
+python_linter: ruff
+use_dispenser: false
+use_github_actions: true
+use_pre_commit: true
use_python_black: true
+use_python_mypy: true
+use_python_pip_audit: true
use_python_pytest: true
diff --git a/tests_generated/test_ide_jetbrains-True/.github/workflows/cd.yaml b/tests_generated/test_ide_jetbrains-True/.github/workflows/cd.yaml
new file mode 100644
index 0000000..3e0fd45
--- /dev/null
+++ b/tests_generated/test_ide_jetbrains-True/.github/workflows/cd.yaml
@@ -0,0 +1,50 @@
+name: Continuous Delivery of Smart Contract
+
+on:
+ push:
+ branches:
+ - main
+
+concurrency: release
+
+jobs:
+ ci-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
+
+ deploy-testnet:
+ runs-on: 'ubuntu-latest'
+ needs: ci-check
+ environment: Test
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Deploy to testnet
+ run: algokit deploy testnet
+ env:
+ # This is the account that becomes the creator of the contract.
+ # Since we are not using the optional dispenser account (via DISPENSER_MNEMONIC),
+ # it must also be funded with enough Algos to deploy and fund the smart contracts created
+ DEPLOYER_MNEMONIC: ${{ secrets.DEPLOYER_MNEMONIC }}
diff --git a/tests_generated/test_ide_jetbrains-True/.github/workflows/checks.yaml b/tests_generated/test_ide_jetbrains-True/.github/workflows/checks.yaml
new file mode 100644
index 0000000..f6d0102
--- /dev/null
+++ b/tests_generated/test_ide_jetbrains-True/.github/workflows/checks.yaml
@@ -0,0 +1,79 @@
+name: Check code base
+
+on:
+ workflow_call:
+
+jobs:
+ checks:
+ runs-on: 'ubuntu-latest'
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Start LocalNet
+ run: algokit localnet start
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Audit with pip-audit
+ run: |
+ # audit non dev dependencies, no exclusions
+ poetry export --without=dev > requirements.txt && poetry run pip-audit -r requirements.txt
+
+ # audit all dependencies, with exclusions.
+ # If a vulnerability is found in a dev dependency without an available fix,
+ # it can be temporarily ignored by adding --ignore-vuln e.g.
+ # --ignore-vuln "GHSA-hcpj-qp55-gfph" # GitPython vulnerability, dev only dependency
+ poetry run pip-audit
+
+ - name: Check formatting with Black
+ run: |
+ # stop the build if there are files that don't meet formatting requirements
+ poetry run black --check .
+
+ - name: Check linting with Ruff
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ poetry run ruff .
+
+ - name: Check types with mypy
+ run: poetry run mypy
+
+ - name: Run tests
+ shell: bash
+ run: |
+ set -o pipefail
+ poetry run pytest --junitxml=pytest-junit.xml
+
+ - name: Build smart contracts
+ run: poetry run python -m smart_contracts build
+
+ - name: Check output stability of the smart contracts
+ shell: bash
+ run: |
+ # Add untracked files as empty so they come up in diff
+ git add -N ./smart_contracts/artifacts
+ # Error out if there are any changes in teal after generating output
+ git diff --exit-code --minimal ./smart_contracts/artifacts || (echo "::error ::Smart contract artifacts have changed, ensure committed artifacts are up to date" && exit 1);
+
+ - name: Run deployer against LocalNet
+ run: poetry run python -m smart_contracts deploy
diff --git a/tests_generated/test_ide_jetbrains-True/.github/workflows/pr.yaml b/tests_generated/test_ide_jetbrains-True/.github/workflows/pr.yaml
new file mode 100644
index 0000000..a80f784
--- /dev/null
+++ b/tests_generated/test_ide_jetbrains-True/.github/workflows/pr.yaml
@@ -0,0 +1,8 @@
+name: Pull Request validation
+
+on: [pull_request]
+
+jobs:
+ pr-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
diff --git a/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build_Beaker_application.xml b/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build_Beaker_application.xml
index 080f919..13f715e 100644
--- a/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build_Beaker_application.xml
+++ b/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build_Beaker_application.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build_Beaker_application____LocalNet.xml b/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build_Beaker_application____LocalNet.xml
index f78fac9..e548132 100644
--- a/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build_Beaker_application____LocalNet.xml
+++ b/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build_Beaker_application____LocalNet.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build___Deploy_Beaker_application.xml b/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build___Deploy_Beaker_application.xml
index d95f2c5..1c1e0bf 100644
--- a/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build___Deploy_Beaker_application.xml
+++ b/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Build___Deploy_Beaker_application.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Deploy_Built_Beaker_application.xml b/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Deploy_Built_Beaker_application.xml
index c2d7413..b3411e8 100644
--- a/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Deploy_Built_Beaker_application.xml
+++ b/tests_generated/test_ide_jetbrains-True/.idea/runConfigurations/Deploy_Built_Beaker_application.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/tests_generated/test_ide_jetbrains-True/.pre-commit-config.yaml b/tests_generated/test_ide_jetbrains-True/.pre-commit-config.yaml
new file mode 100644
index 0000000..93bfff5
--- /dev/null
+++ b/tests_generated/test_ide_jetbrains-True/.pre-commit-config.yaml
@@ -0,0 +1,38 @@
+repos:
+ - repo: local
+ hooks:
+
+ - id: black
+ name: black
+ description: "Black: The uncompromising Python code formatter"
+ entry: poetry run black
+ language: system
+ minimum_pre_commit_version: 2.9.2
+ require_serial: true
+ types_or: [ python, pyi ]
+
+
+ - id: ruff
+ name: ruff
+ description: "Run 'ruff' for extremely fast Python linting"
+ entry: poetry run ruff
+ language: system
+ types: [ python ]
+ args: [ --fix ]
+ require_serial: false
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '0'
+ files: '^(src|tests)/'
+
+
+ - id: mypy
+ name: mypy
+ description: '`mypy` will check Python types for correctness'
+ entry: poetry run mypy
+ language: system
+ types_or: [ python, pyi ]
+ require_serial: true
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '2.9.2'
+ files: '^(src|tests)/'
+
diff --git a/tests_generated/test_ide_jetbrains-True/.vscode/extensions.json b/tests_generated/test_ide_jetbrains-True/.vscode/extensions.json
index 9a7b7f1..36d7c10 100644
--- a/tests_generated/test_ide_jetbrains-True/.vscode/extensions.json
+++ b/tests_generated/test_ide_jetbrains-True/.vscode/extensions.json
@@ -1,6 +1,8 @@
{
"recommendations": [
"ms-python.python",
+ "charliermarsh.ruff",
+ "matangover.mypy",
"ms-python.black-formatter",
"tamasfe.even-better-toml",
"editorconfig.editorconfig"
diff --git a/tests_generated/test_ide_jetbrains-True/.vscode/launch.json b/tests_generated/test_ide_jetbrains-True/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_ide_jetbrains-True/.vscode/launch.json
+++ b/tests_generated/test_ide_jetbrains-True/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_ide_jetbrains-True/.vscode/settings.json b/tests_generated/test_ide_jetbrains-True/.vscode/settings.json
index c2cc2b6..0c2dfec 100644
--- a/tests_generated/test_ide_jetbrains-True/.vscode/settings.json
+++ b/tests_generated/test_ide_jetbrains-True/.vscode/settings.json
@@ -25,6 +25,23 @@
},
"black-formatter.args": ["--config=pyproject.toml"],
"python.testing.pytestEnabled": true,
+ "ruff.enable": true,
+ "ruff.lint.run": "onSave",
+ "ruff.lint.args": ["--config=pyproject.toml"],
+ "ruff.importStrategy": "fromEnvironment",
+ "ruff.fixAll": true, //lint and fix all files in workspace
+ "ruff.organizeImports": true, //organize imports on save
+ "ruff.codeAction.disableRuleComment": {
+ "enable": true
+ },
+ "ruff.codeAction.fixViolation": {
+ "enable": true
+ },
+ "python.analysis.typeCheckingMode": "off",
+ "mypy.configFile": "pyproject.toml",
+ // set to empty array to use config from project
+ "mypy.targets": [],
+ "mypy.runUsingActiveInterpreter": true,
// On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
// so instead let's set it to RemoteSigned for VS Code terminal
diff --git a/tests_generated/test_ide_jetbrains-True/.vscode/tasks.json b/tests_generated/test_ide_jetbrains-True/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_ide_jetbrains-True/.vscode/tasks.json
+++ b/tests_generated/test_ide_jetbrains-True/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_ide_jetbrains-True/README.md b/tests_generated/test_ide_jetbrains-True/README.md
index fea3e9f..e6071df 100644
--- a/tests_generated/test_ide_jetbrains-True/README.md
+++ b/tests_generated/test_ide_jetbrains-True/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -39,7 +46,46 @@ This project has been generated using AlgoKit. See below for default getting sta
1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
2. Follow step 3 above
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
+> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.### Continuous Integration / Continuous Deployment (CI/CD)
+
+This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI/CD workflows, which are located in the [`.github/workflows`](./.github/workflows) folder.
+
+#### Setting up GitHub for CI/CD workflow and TestNet deployment
+
+ 1. Every time you have a change to your smart contract, and when you first initialize the project you need to [build the contract](#initial-setup) and then commit the `smart_contracts/artifacts` folder so the [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) tests pass
+ 2. Decide what values you want to use for the `allow_update`, `allow_delete` and the `on_schema_break`, `on_update` parameters specified in [`contract.py`](./smart_contracts/hello_world/contract.py).
+ When deploying to LocalNet these values are both set to allow update and replacement of the app for convenience. But for non-LocalNet networks
+ the defaults are more conservative.
+ These default values will allow the smart contract to be deployed initially, but will not allow the app to be updated or deleted if is changed and the build will instead fail.
+ To help you decide it may be helpful to read the [AlgoKit Utils app deployment documentation](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/app-deploy.md) or the [AlgoKit smart contract deployment architecture](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md#upgradeable-and-deletable-contracts).
+ 3. Create a [Github Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#creating-an-environment) named `Test`.
+ Note: If you have a private repository and don't have GitHub Enterprise then Environments won't work and you'll need to convert the GitHub Action to use a different approach. Ignore this step if you picked `Starter` preset.
+ 4. Create or obtain a mnemonic for an Algorand account for use on TestNet to deploy apps, referred to as the `DEPLOYER` account.
+ 5. Store the mnemonic as a [secret](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-secrets) `DEPLOYER_MNEMONIC`
+ in the Test environment created in step 3.
+ 6. The account used to deploy the smart contract will require enough funds to create the app, and also fund it. There are two approaches available here:
+ * Either, ensure the account is funded outside of CI/CD.
+ In Testnet, funds can be obtained by using the [Algorand TestNet dispenser](https://bank.testnet.algorand.network/) and we recommend provisioning 50 ALGOs.
+ * Or, fund the account as part of the CI/CD process by using a `DISPENSER_MNEMONIC` GitHub Environment secret to point to a separate `DISPENSER` account that you maintain ALGOs in (similarly, you need to provision ALGOs into this account using the [TestNet dispenser](https://bank.testnet.algorand.network/)).
+
+#### Continuous Integration
+
+For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions:
+ - Python dependencies are audited using [pip-audit](https://pypi.org/project/pip-audit/)
+ - Code formatting is checked using [Black](https://github.com/psf/black)
+ - Linting is checked using [Ruff](https://github.com/charliermarsh/ruff)
+ - Types are checked using [mypy](https://mypy-lang.org/)
+ - Python tests are executed using [pytest](https://docs.pytest.org/)
+ - Smart contract artifacts are built
+ - Smart contract artifacts are checked for [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md)
+ - Smart contract is deployed to a AlgoKit LocalNet instance
+
+#### Continuous Deployment
+
+For pushes to `main` branch, after the above checks pass, the following deployment actions are performed:
+ - The smart contract(s) are deployed to TestNet using [AlgoNode](https://algonode.io).
+
+> Please note deployment is also performed via `algokit deploy` command which can be invoked both via CI as seen on this project, or locally. For more information on how to use `algokit deploy` please see [AlgoKit documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/deploy.md).
# Tools
@@ -47,11 +93,14 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
+- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
+
+- [mypy](https://mypy-lang.org/): Static type checker.
- [pytest](https://docs.pytest.org/): Automated testing.
- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
+ - [pre-commit](https://pre-commit.com/): A framework for managing and maintaining multi-language pre-commit hooks, to enable pre-commit you need to run `pre-commit install` in the root of the repository. This will install the pre-commit hooks and run them against modified files when committing. If any of the hooks fail, the commit will be aborted. To run the hooks on all files, use `pre-commit run --all-files`.
It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder.
diff --git a/tests_generated/test_ide_jetbrains-True/pyproject.toml b/tests_generated/test_ide_jetbrains-True/pyproject.toml
index 5c863e9..c7f3a15 100644
--- a/tests_generated/test_ide_jetbrains-True/pyproject.toml
+++ b/tests_generated/test_ide_jetbrains-True/pyproject.toml
@@ -6,21 +6,45 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
+ruff = "^0.1.6"
+mypy = "*"
pytest = "*"
pytest-cov = "*"
pip-audit = "*"
+pre-commit = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
+[tool.ruff]
+line-length = 120
+select = ["E", "F", "ANN", "UP", "N", "C4", "B", "A", "YTT", "W", "FBT", "Q", "RUF", "I"]
+ignore = [
+ "ANN101", # no type for self
+ "ANN102", # no type for cls
+]
+unfixable = ["B", "RUF"]
+
+[tool.ruff.flake8-annotations]
+allow-star-arg-any = true
+suppress-none-returning = true
[tool.pytest.ini_options]
pythonpath = ["smart_contracts", "tests"]
+
+[tool.mypy]
+files = "smart_contracts/"
+python_version = "3.12"
+check_untyped_defs = true
+warn_redundant_casts = true
+warn_unused_ignores = true
+allow_untyped_defs = false
+strict_equality = true
diff --git a/tests_generated/test_ide_jetbrains-True/smart_contracts/__main__.py b/tests_generated/test_ide_jetbrains-True/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_ide_jetbrains-True/smart_contracts/__main__.py
+++ b/tests_generated/test_ide_jetbrains-True/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_ide_jetbrains-True/smart_contracts/config.py b/tests_generated/test_ide_jetbrains-True/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_ide_jetbrains-True/smart_contracts/config.py
+++ b/tests_generated/test_ide_jetbrains-True/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_ide_jetbrains-True/smart_contracts/hello_world/contract.py b/tests_generated/test_ide_jetbrains-True/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_ide_jetbrains-True/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_ide_jetbrains-True/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_ide_jetbrains-True/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_ide_jetbrains-True/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_ide_jetbrains-True/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_ide_jetbrains-True/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_ide_jetbrains-True/smart_contracts/helpers/build.py b/tests_generated/test_ide_jetbrains-True/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_ide_jetbrains-True/smart_contracts/helpers/build.py
+++ b/tests_generated/test_ide_jetbrains-True/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_ide_jetbrains-True/tests/hello_world_test.py b/tests_generated/test_ide_jetbrains-True/tests/hello_world_test.py
index 50fd332..f4262b9 100644
--- a/tests_generated/test_ide_jetbrains-True/tests/hello_world_test.py
+++ b/tests_generated/test_ide_jetbrains-True/tests/hello_world_test.py
@@ -1,33 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_ide_vscode-False/.algokit.toml b/tests_generated/test_ide_vscode-False/.algokit.toml
deleted file mode 100644
index 77dfd4b..0000000
--- a/tests_generated/test_ide_vscode-False/.algokit.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[algokit]
-min_version = "v1.7.3"
-
-[deploy]
-command = "poetry run python -m smart_contracts deploy"
-environment_secrets = [
- "DEPLOYER_MNEMONIC",
-]
-
-[deploy.localnet]
-environment_secrets = []
-
-[generate.smart_contract]
-description = "Adds new smart contract to existing project"
-path = ".algokit/generators/create_contract"
diff --git a/tests_generated/test_ide_vscode-False/.copier-answers.yml b/tests_generated/test_ide_vscode-False/.copier-answers.yml
deleted file mode 100644
index 4db11ed..0000000
--- a/tests_generated/test_ide_vscode-False/.copier-answers.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
-_commit:
-_src_path:
-algod_port: 4001
-algod_server: http://localhost
-algod_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-author_email: None
-author_name: None
-contract_name: hello_world
-deployment_language: python
-ide_jetbrains: false
-ide_vscode: false
-indexer_port: 8980
-indexer_server: http://localhost
-indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
-project_name: test_ide_vscode-False
-use_python_black: true
-use_python_pytest: true
-
diff --git a/tests_generated/test_ide_vscode-False/.editorconfig b/tests_generated/test_ide_vscode-False/.editorconfig
deleted file mode 100644
index e2fda34..0000000
--- a/tests_generated/test_ide_vscode-False/.editorconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-root=true
-
-[*]
-indent_style = space
-indent_size = 2
-end_of_line = lf
-insert_final_newline = true
-
-[*.py]
-indent_size = 4
diff --git a/tests_generated/test_ide_vscode-False/.env.localnet.template b/tests_generated/test_ide_vscode-False/.env.localnet.template
deleted file mode 100644
index fcbf442..0000000
--- a/tests_generated/test_ide_vscode-False/.env.localnet.template
+++ /dev/null
@@ -1,7 +0,0 @@
-# this file should contain environment variables specific to algokit localnet
-ALGOD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-ALGOD_SERVER=http://localhost
-ALGOD_PORT=4001
-INDEXER_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-INDEXER_SERVER=http://localhost
-INDEXER_PORT=8980
diff --git a/tests_generated/test_ide_vscode-False/.env.template b/tests_generated/test_ide_vscode-False/.env.template
deleted file mode 100644
index 184b393..0000000
--- a/tests_generated/test_ide_vscode-False/.env.template
+++ /dev/null
@@ -1 +0,0 @@
-# this file should contain environment variables common to all environments/networks
diff --git a/tests_generated/test_ide_vscode-False/.env.testnet.template b/tests_generated/test_ide_vscode-False/.env.testnet.template
deleted file mode 100644
index eeea43d..0000000
--- a/tests_generated/test_ide_vscode-False/.env.testnet.template
+++ /dev/null
@@ -1,3 +0,0 @@
-# this file contains algorand network settings for interacting with testnet via algonode
-ALGOD_SERVER=https://testnet-api.algonode.cloud
-INDEXER_SERVER=https://testnet-idx.algonode.cloud
diff --git a/tests_generated/test_ide_vscode-False/.gitattributes b/tests_generated/test_ide_vscode-False/.gitattributes
deleted file mode 100644
index 6313b56..0000000
--- a/tests_generated/test_ide_vscode-False/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-* text=auto eol=lf
diff --git a/tests_generated/test_ide_vscode-False/.gitignore b/tests_generated/test_ide_vscode-False/.gitignore
deleted file mode 100644
index 832924c..0000000
--- a/tests_generated/test_ide_vscode-False/.gitignore
+++ /dev/null
@@ -1,174 +0,0 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-cover/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-.pybuilder/
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-# For a library or package, you might want to ignore these files since the code is
-# intended to run in multiple environments; otherwise, check them in:
-# .python-version
-
-# pipenv
-# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-# However, in case of collaboration, if having platform-specific dependencies or dependencies
-# having no cross-platform support, pipenv may install dependencies that don't work, or not
-# install all needed dependencies.
-#Pipfile.lock
-
-# poetry
-# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
-# This is especially recommended for binary packages to ensure reproducibility, and is more
-# commonly ignored for libraries.
-# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
-#poetry.lock
-
-# pdm
-# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
-#pdm.lock
-# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
-# in version control.
-# https://pdm.fming.dev/#use-with-ide
-.pdm.toml
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-.env.*
-!.env.*.template
-!.env.template
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-# pytype static type analyzer
-.pytype/
-
-# Ruff (linter)
-.ruff_cache/
-
-# Cython debug symbols
-cython_debug/
-
-# PyCharm
-.idea
-!.idea/
-.idea/*
-!.idea/runConfigurations/
-
-# macOS
-.DS_Store
-
-# Received approval test files
-*.received.*
-
-# NPM
-node_modules
diff --git a/tests_generated/test_ide_vscode-False/README.md b/tests_generated/test_ide_vscode-False/README.md
deleted file mode 100644
index ca6a618..0000000
--- a/tests_generated/test_ide_vscode-False/README.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# test_ide_vscode-False
-
-This project has been generated using AlgoKit. See below for default getting started instructions.
-
-# Setup
-
-### Initial setup
-
-1. Clone this repository locally
-2. Install pre-requisites:
- - Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
- - Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
- - Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- - Copy `.env.template` to `.env`
- - Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
-3. Open the project and start debugging / developing via:
- - VS Code
- 1. Open the repository root in VS Code
- 2. Install recommended extensions
- 3. Hit F5 (or whatever you have debug mapped to) and it should start running with breakpoint debugging.
- > **Note**
- > If using Windows: Before running for the first time you will need to select the Python Interpreter.
- 1. Open the command palette (Ctrl/Cmd + Shift + P)
- 2. Search for `Python: Select Interpreter`
- 3. Select `./.venv/Scripts/python.exe`
- - JetBrains IDEs (please note, this setup is primarily optimized for PyCharm Community Edition)
- 1. Open the repository root in the IDE
- 2. It should automatically detect it's a Poetry project and set up a Python interpreter and virtual environment.
- 3. Hit Shift+F10|Ctrl+R (or whatever you have debug mapped to) and it should start running with breakpoint debugging. Please note, JetBrains IDEs on Windows have a known bug that in some cases may prevent executing shell scripts as pre-launch tasks, for workarounds refer to [JetBrains forums](https://youtrack.jetbrains.com/issue/IDEA-277486/Shell-script-configuration-cannot-run-as-before-launch-task).
- - Other
- 1. Open the repository root in your text editor of choice
- 2. In a terminal run `poetry shell`
- 3. Run `python -m smart_contracts` through your debugger of choice
-
-### Subsequently
-
-1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
-2. Follow step 3 above
-
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
-
-# Tools
-
-This project makes use of Python to build Algorand smart contracts. The following tools are in use:
-
-- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
-- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
-- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
-- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
-- [pytest](https://docs.pytest.org/): Automated testing.
-- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
diff --git a/tests_generated/test_ide_vscode-False/poetry.toml b/tests_generated/test_ide_vscode-False/poetry.toml
deleted file mode 100644
index ab1033b..0000000
--- a/tests_generated/test_ide_vscode-False/poetry.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[virtualenvs]
-in-project = true
diff --git a/tests_generated/test_ide_vscode-False/pyproject.toml b/tests_generated/test_ide_vscode-False/pyproject.toml
deleted file mode 100644
index decb76c..0000000
--- a/tests_generated/test_ide_vscode-False/pyproject.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[tool.poetry]
-name = "test_ide_vscode-False"
-version = "0.1.0"
-description = "Algorand smart contracts"
-authors = ["None "]
-readme = "README.md"
-
-[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
-algokit-utils = "^2.0.1"
-python-dotenv = "^1.0.0"
-
-[tool.poetry.group.dev.dependencies]
-black = {extras = ["d"], version = "*"}
-pytest = "*"
-pytest-cov = "*"
-pip-audit = "*"
-
-[build-system]
-requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
-
-
-[tool.pytest.ini_options]
-pythonpath = ["smart_contracts", "tests"]
diff --git a/tests_generated/test_ide_vscode-False/smart_contracts/README.md b/tests_generated/test_ide_vscode-False/smart_contracts/README.md
deleted file mode 100644
index f765c95..0000000
--- a/tests_generated/test_ide_vscode-False/smart_contracts/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-## How to add new smart contracts?
-
-By the default the template creates a single `HelloWorld` contract under hello_world folder in the `smart_contracts` directory. To add a new contract:
-
-1. From the root of the project (`../`) execute `algokit generate smart-contract`. This will create a new starter smart contract and deployment configuration file under `{your_contract_name}` subfolder under `smart_contracts` directory.
-2. Each contract potentially has different creation parameters and deployment steps. Hence, you need to define your deployment logic in `deploy_config.py`file.
-3. `config.py` file will automatically build all contracts under `smart_contracts` directory. If you want to build specific contracts manually, modify the default code provided by the template in `config.py` file.
-
-> Please note, above is just a suggested convention tailored for the base configuration and structure of this template. Default code supplied by the template in `config.py` and `index.ts` (if using ts clients) files are tailored for the suggested convention. You are free to modify the structure and naming conventions as you see fit.
diff --git a/tests_generated/test_ide_vscode-False/smart_contracts/__init__.py b/tests_generated/test_ide_vscode-False/smart_contracts/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_ide_vscode-False/smart_contracts/__main__.py b/tests_generated/test_ide_vscode-False/smart_contracts/__main__.py
deleted file mode 100644
index 3ef8a27..0000000
--- a/tests_generated/test_ide_vscode-False/smart_contracts/__main__.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import logging
-import sys
-from pathlib import Path
-
-from dotenv import load_dotenv
-
-from smart_contracts.config import contracts
-from smart_contracts.helpers.build import build
-from smart_contracts.helpers.deploy import deploy
-
-logging.basicConfig(
- level=logging.DEBUG, format="%(asctime)s %(levelname)-10s: %(message)s"
-)
-logger = logging.getLogger(__name__)
-logger.info("Loading .env")
-load_dotenv()
-root_path = Path(__file__).parent
-
-
-def main(action: str) -> None:
- artifact_path = root_path / "artifacts"
- match action:
- case "build":
- for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
- case "deploy":
- for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
- if contract.deploy:
- deploy(app_spec_path, contract.deploy)
- case "all":
- for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
- if contract.deploy:
- deploy(app_spec_path, contract.deploy)
-
-
-if __name__ == "__main__":
- if len(sys.argv) > 1:
- main(sys.argv[1])
- else:
- main("all")
diff --git a/tests_generated/test_ide_vscode-False/smart_contracts/config.py b/tests_generated/test_ide_vscode-False/smart_contracts/config.py
deleted file mode 100644
index 8cefdd6..0000000
--- a/tests_generated/test_ide_vscode-False/smart_contracts/config.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import dataclasses
-import importlib
-from collections.abc import Callable
-from pathlib import Path
-
-from algokit_utils import Account, ApplicationSpecification
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
-
-
-@dataclasses.dataclass
-class SmartContract:
- app: Application
- deploy: Callable[
- [AlgodClient, IndexerClient, ApplicationSpecification, Account], None
- ] | None = None
-
-
-def import_contract(folder: Path) -> Application:
- """Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
-
-
-def import_deploy_if_exists(
- folder: Path,
-) -> (
- Callable[[AlgodClient, IndexerClient, ApplicationSpecification, Account], None]
- | None
-):
- """Imports the deploy function from a folder if it exists."""
- try:
- deploy_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.deploy_config"
- )
- return deploy_module.deploy
- except ImportError:
- return None
-
-
-def has_contract_file(directory: Path) -> bool:
- """Checks whether the directory contains contract.py file."""
- return (directory / "contract.py").exists()
-
-
-# define contracts to build and/or deploy
-base_dir = Path("smart_contracts")
-contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
- for folder in base_dir.iterdir()
- if folder.is_dir() and has_contract_file(folder)
-]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_ide_vscode-False/smart_contracts/hello_world/contract.py b/tests_generated/test_ide_vscode-False/smart_contracts/hello_world/contract.py
deleted file mode 100644
index 5ed8de0..0000000
--- a/tests_generated/test_ide_vscode-False/smart_contracts/hello_world/contract.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import beaker
-import pyteal as pt
-
-
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
diff --git a/tests_generated/test_ide_vscode-False/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_ide_vscode-False/smart_contracts/hello_world/deploy_config.py
deleted file mode 100644
index 4afdc60..0000000
--- a/tests_generated/test_ide_vscode-False/smart_contracts/hello_world/deploy_config.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import logging
-
-import algokit_utils
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-
-logger = logging.getLogger(__name__)
-
-
-# define deployment behaviour based on supplied app spec
-def deploy(
- algod_client: AlgodClient,
- indexer_client: IndexerClient,
- app_spec: algokit_utils.ApplicationSpecification,
- deployer: algokit_utils.Account,
-) -> None:
- from smart_contracts.artifacts.hello_world.client import (
- HelloWorldClient,
- )
-
- app_client = HelloWorldClient(
- algod_client,
- creator=deployer,
- indexer_client=indexer_client,
- )
- app_client.deploy(
- on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
- on_update=algokit_utils.OnUpdate.AppendApp,
- )
-
- name = "world"
- response = app_client.hello(name=name)
- logger.info(
- f"Called hello on {app_spec.contract.name} ({app_client.app_id}) "
- f"with name={name}, received: {response.return_value}"
- )
diff --git a/tests_generated/test_ide_vscode-False/smart_contracts/helpers/__init__.py b/tests_generated/test_ide_vscode-False/smart_contracts/helpers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_ide_vscode-False/smart_contracts/helpers/build.py b/tests_generated/test_ide_vscode-False/smart_contracts/helpers/build.py
deleted file mode 100644
index 201e5d6..0000000
--- a/tests_generated/test_ide_vscode-False/smart_contracts/helpers/build.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import logging
-import subprocess
-from pathlib import Path
-from shutil import rmtree
-
-import beaker
-
-logger = logging.getLogger(__name__)
-deployment_extension = "py"
-
-
-def build(output_dir: Path, app: beaker.Application) -> Path:
- output_dir = output_dir.resolve()
- if output_dir.exists():
- rmtree(output_dir)
- output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
-
- result = subprocess.run(
- [
- "algokit",
- "generate",
- "client",
- output_dir / "application.json",
- "--output",
- output_dir / f"client.{deployment_extension}",
- ],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- text=True,
- )
- if result.returncode:
- if "No such command" in result.stdout:
- raise Exception(
- "Could not generate typed client, requires AlgoKit 1.1 or "
- "later. Please update AlgoKit"
- )
- else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
- return output_dir / "application.json"
diff --git a/tests_generated/test_ide_vscode-False/smart_contracts/helpers/deploy.py b/tests_generated/test_ide_vscode-False/smart_contracts/helpers/deploy.py
deleted file mode 100644
index 08367a3..0000000
--- a/tests_generated/test_ide_vscode-False/smart_contracts/helpers/deploy.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import logging
-from collections.abc import Callable
-from pathlib import Path
-
-from algokit_utils import (
- Account,
- ApplicationSpecification,
- EnsureBalanceParameters,
- ensure_funded,
- get_account,
- get_algod_client,
- get_indexer_client,
-)
-from algosdk.util import algos_to_microalgos
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-
-logger = logging.getLogger(__name__)
-
-
-def deploy(
- app_spec_path: Path,
- deploy_callback: Callable[
- [AlgodClient, IndexerClient, ApplicationSpecification, Account], None
- ],
- deployer_initial_funds: int = 2,
-) -> None:
- # get clients
- # by default client configuration is loaded from environment variables
- algod_client = get_algod_client()
- indexer_client = get_indexer_client()
-
- # get app spec
- app_spec = ApplicationSpecification.from_json(app_spec_path.read_text())
-
- # get deployer account by name
- deployer = get_account(algod_client, "DEPLOYER", fund_with_algos=0)
-
- minimum_funds_micro_algos = algos_to_microalgos(deployer_initial_funds)
- ensure_funded(
- algod_client,
- EnsureBalanceParameters(
- account_to_fund=deployer,
- min_spending_balance_micro_algos=minimum_funds_micro_algos,
- min_funding_increment_micro_algos=minimum_funds_micro_algos,
- ),
- )
-
- # use provided callback to deploy the app
- deploy_callback(algod_client, indexer_client, app_spec, deployer)
diff --git a/tests_generated/test_ide_vscode-False/tests/__init__.py b/tests_generated/test_ide_vscode-False/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_ide_vscode-False/tests/conftest.py b/tests_generated/test_ide_vscode-False/tests/conftest.py
deleted file mode 100644
index 06a89eb..0000000
--- a/tests_generated/test_ide_vscode-False/tests/conftest.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from pathlib import Path
-
-import pytest
-from algokit_utils import (
- get_algod_client,
- is_localnet,
-)
-from algosdk.v2client.algod import AlgodClient
-from dotenv import load_dotenv
-
-
-@pytest.fixture(autouse=True, scope="session")
-def environment_fixture() -> None:
- env_path = Path(__file__).parent.parent / ".env.localnet"
- load_dotenv(env_path)
-
-
-@pytest.fixture(scope="session")
-def algod_client() -> AlgodClient:
- client = get_algod_client()
-
- # you can remove this assertion to test on other networks,
- # included here to prevent accidentally running against other networks
- assert is_localnet(client)
- return client
diff --git a/tests_generated/test_ide_vscode-False/tests/hello_world_test.py b/tests_generated/test_ide_vscode-False/tests/hello_world_test.py
deleted file mode 100644
index 50fd332..0000000
--- a/tests_generated/test_ide_vscode-False/tests/hello_world_test.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
-from algosdk.v2client.algod import AlgodClient
-
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
-
-
-@pytest.fixture(scope="session")
-def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
- algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
- )
- client.create()
- return client
-
-
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
-
- assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_ide_vscode-True/.algokit.toml b/tests_generated/test_ide_vscode-True/.algokit.toml
deleted file mode 100644
index 77dfd4b..0000000
--- a/tests_generated/test_ide_vscode-True/.algokit.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[algokit]
-min_version = "v1.7.3"
-
-[deploy]
-command = "poetry run python -m smart_contracts deploy"
-environment_secrets = [
- "DEPLOYER_MNEMONIC",
-]
-
-[deploy.localnet]
-environment_secrets = []
-
-[generate.smart_contract]
-description = "Adds new smart contract to existing project"
-path = ".algokit/generators/create_contract"
diff --git a/tests_generated/test_ide_vscode-True/.copier-answers.yml b/tests_generated/test_ide_vscode-True/.copier-answers.yml
deleted file mode 100644
index 38a4291..0000000
--- a/tests_generated/test_ide_vscode-True/.copier-answers.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
-_commit:
-_src_path:
-algod_port: 4001
-algod_server: http://localhost
-algod_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-author_email: None
-author_name: None
-contract_name: hello_world
-deployment_language: python
-ide_vscode: true
-indexer_port: 8980
-indexer_server: http://localhost
-indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
-project_name: test_ide_vscode-True
-use_python_black: true
-use_python_pytest: true
-
diff --git a/tests_generated/test_ide_vscode-True/.editorconfig b/tests_generated/test_ide_vscode-True/.editorconfig
deleted file mode 100644
index e2fda34..0000000
--- a/tests_generated/test_ide_vscode-True/.editorconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-root=true
-
-[*]
-indent_style = space
-indent_size = 2
-end_of_line = lf
-insert_final_newline = true
-
-[*.py]
-indent_size = 4
diff --git a/tests_generated/test_ide_vscode-True/.env.localnet.template b/tests_generated/test_ide_vscode-True/.env.localnet.template
deleted file mode 100644
index fcbf442..0000000
--- a/tests_generated/test_ide_vscode-True/.env.localnet.template
+++ /dev/null
@@ -1,7 +0,0 @@
-# this file should contain environment variables specific to algokit localnet
-ALGOD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-ALGOD_SERVER=http://localhost
-ALGOD_PORT=4001
-INDEXER_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-INDEXER_SERVER=http://localhost
-INDEXER_PORT=8980
diff --git a/tests_generated/test_ide_vscode-True/.env.template b/tests_generated/test_ide_vscode-True/.env.template
deleted file mode 100644
index 184b393..0000000
--- a/tests_generated/test_ide_vscode-True/.env.template
+++ /dev/null
@@ -1 +0,0 @@
-# this file should contain environment variables common to all environments/networks
diff --git a/tests_generated/test_ide_vscode-True/.env.testnet.template b/tests_generated/test_ide_vscode-True/.env.testnet.template
deleted file mode 100644
index eeea43d..0000000
--- a/tests_generated/test_ide_vscode-True/.env.testnet.template
+++ /dev/null
@@ -1,3 +0,0 @@
-# this file contains algorand network settings for interacting with testnet via algonode
-ALGOD_SERVER=https://testnet-api.algonode.cloud
-INDEXER_SERVER=https://testnet-idx.algonode.cloud
diff --git a/tests_generated/test_ide_vscode-True/.gitattributes b/tests_generated/test_ide_vscode-True/.gitattributes
deleted file mode 100644
index 6313b56..0000000
--- a/tests_generated/test_ide_vscode-True/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-* text=auto eol=lf
diff --git a/tests_generated/test_ide_vscode-True/.gitignore b/tests_generated/test_ide_vscode-True/.gitignore
deleted file mode 100644
index 832924c..0000000
--- a/tests_generated/test_ide_vscode-True/.gitignore
+++ /dev/null
@@ -1,174 +0,0 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-cover/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-.pybuilder/
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-# For a library or package, you might want to ignore these files since the code is
-# intended to run in multiple environments; otherwise, check them in:
-# .python-version
-
-# pipenv
-# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-# However, in case of collaboration, if having platform-specific dependencies or dependencies
-# having no cross-platform support, pipenv may install dependencies that don't work, or not
-# install all needed dependencies.
-#Pipfile.lock
-
-# poetry
-# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
-# This is especially recommended for binary packages to ensure reproducibility, and is more
-# commonly ignored for libraries.
-# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
-#poetry.lock
-
-# pdm
-# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
-#pdm.lock
-# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
-# in version control.
-# https://pdm.fming.dev/#use-with-ide
-.pdm.toml
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-.env.*
-!.env.*.template
-!.env.template
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-# pytype static type analyzer
-.pytype/
-
-# Ruff (linter)
-.ruff_cache/
-
-# Cython debug symbols
-cython_debug/
-
-# PyCharm
-.idea
-!.idea/
-.idea/*
-!.idea/runConfigurations/
-
-# macOS
-.DS_Store
-
-# Received approval test files
-*.received.*
-
-# NPM
-node_modules
diff --git a/tests_generated/test_ide_vscode-True/.vscode/extensions.json b/tests_generated/test_ide_vscode-True/.vscode/extensions.json
deleted file mode 100644
index 9a7b7f1..0000000
--- a/tests_generated/test_ide_vscode-True/.vscode/extensions.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "recommendations": [
- "ms-python.python",
- "ms-python.black-formatter",
- "tamasfe.even-better-toml",
- "editorconfig.editorconfig"
- ]
-}
diff --git a/tests_generated/test_ide_vscode-True/.vscode/launch.json b/tests_generated/test_ide_vscode-True/.vscode/launch.json
deleted file mode 100644
index 8a39d26..0000000
--- a/tests_generated/test_ide_vscode-True/.vscode/launch.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Build & Deploy Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "cwd": "${workspaceFolder}",
- "preLaunchTask": "Start AlgoKit LocalNet",
- "envFile": "${workspaceFolder}/.env.localnet"
- },
- {
- "name": "Deploy Built Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "args": ["deploy"],
- "cwd": "${workspaceFolder}",
- "envFile": "${workspaceFolder}/.env.localnet"
- },
- {
- "name": "Build Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "args": ["build"],
- "cwd": "${workspaceFolder}"
- }
- ]
-}
diff --git a/tests_generated/test_ide_vscode-True/.vscode/settings.json b/tests_generated/test_ide_vscode-True/.vscode/settings.json
deleted file mode 100644
index c2cc2b6..0000000
--- a/tests_generated/test_ide_vscode-True/.vscode/settings.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- // General - see also /.editorconfig
- "editor.formatOnSave": true,
- "files.exclude": {
- "**/.git": true,
- "**/.DS_Store": true,
- "**/Thumbs.db": true,
- ".mypy_cache": true,
- ".pytest_cache": true,
- ".ruff_cache": true,
- "**/__pycache__": true,
- ".idea": true
- },
-
- // Python
- "python.analysis.extraPaths": ["${workspaceFolder}/smart_contracts"],
- "python.defaultInterpreterPath": "${workspaceFolder}/.venv",
- "[python]": {
- "editor.codeActionsOnSave": {
- "source.fixAll": true,
- // Prevent default import sorting from running; Ruff will sort imports for us anyway
- "source.organizeImports": false
- },
- "editor.defaultFormatter": "ms-python.black-formatter",
- },
- "black-formatter.args": ["--config=pyproject.toml"],
- "python.testing.pytestEnabled": true,
-
- // On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
- // so instead let's set it to RemoteSigned for VS Code terminal
- "terminal.integrated.shellArgs.windows": ["-ExecutionPolicy", "RemoteSigned"],
-}
diff --git a/tests_generated/test_ide_vscode-True/.vscode/tasks.json b/tests_generated/test_ide_vscode-True/.vscode/tasks.json
deleted file mode 100644
index fe7889a..0000000
--- a/tests_generated/test_ide_vscode-True/.vscode/tasks.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "version": "2.0.0",
- "tasks": [
- {
- "label": "Build Beaker application",
- "command": "${workspaceFolder}/.venv/bin/python",
- "windows": {
- "command": "${workspaceFolder}/.venv/Scripts/python.exe"
- },
- "args": ["-m", "smart_contracts", "build"],
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "group": {
- "kind": "build",
- "isDefault": true
- },
- "problemMatcher": []
- },
- {
- "label": "Build Beaker application (+ LocalNet)",
- "command": "${workspaceFolder}/.venv/bin/python",
- "windows": {
- "command": "${workspaceFolder}/.venv/Scripts/python.exe"
- },
- "args": ["-m", "smart_contracts", "build"],
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "dependsOn": "Start AlgoKit LocalNet",
- "problemMatcher": []
- },
- {
- "label": "Start AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "start"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- },
- {
- "label": "Stop AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "stop"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- },
- {
- "label": "Reset AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "reset"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- }
- ]
-}
diff --git a/tests_generated/test_ide_vscode-True/README.md b/tests_generated/test_ide_vscode-True/README.md
deleted file mode 100644
index cf1e915..0000000
--- a/tests_generated/test_ide_vscode-True/README.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# test_ide_vscode-True
-
-This project has been generated using AlgoKit. See below for default getting started instructions.
-
-# Setup
-
-### Initial setup
-
-1. Clone this repository locally
-2. Install pre-requisites:
- - Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
- - Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
- - Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- - Copy `.env.template` to `.env`
- - Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
-3. Open the project and start debugging / developing via:
- - VS Code
- 1. Open the repository root in VS Code
- 2. Install recommended extensions
- 3. Hit F5 (or whatever you have debug mapped to) and it should start running with breakpoint debugging.
- > **Note**
- > If using Windows: Before running for the first time you will need to select the Python Interpreter.
- 1. Open the command palette (Ctrl/Cmd + Shift + P)
- 2. Search for `Python: Select Interpreter`
- 3. Select `./.venv/Scripts/python.exe`
- - JetBrains IDEs (please note, this setup is primarily optimized for PyCharm Community Edition)
- 1. Open the repository root in the IDE
- 2. It should automatically detect it's a Poetry project and set up a Python interpreter and virtual environment.
- 3. Hit Shift+F10|Ctrl+R (or whatever you have debug mapped to) and it should start running with breakpoint debugging. Please note, JetBrains IDEs on Windows have a known bug that in some cases may prevent executing shell scripts as pre-launch tasks, for workarounds refer to [JetBrains forums](https://youtrack.jetbrains.com/issue/IDEA-277486/Shell-script-configuration-cannot-run-as-before-launch-task).
- - Other
- 1. Open the repository root in your text editor of choice
- 2. In a terminal run `poetry shell`
- 3. Run `python -m smart_contracts` through your debugger of choice
-
-### Subsequently
-
-1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
-2. Follow step 3 above
-
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
-
-# Tools
-
-This project makes use of Python to build Algorand smart contracts. The following tools are in use:
-
-- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
-- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
-- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
-- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
-- [pytest](https://docs.pytest.org/): Automated testing.
-- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
-It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder.
-
diff --git a/tests_generated/test_ide_vscode-True/poetry.toml b/tests_generated/test_ide_vscode-True/poetry.toml
deleted file mode 100644
index ab1033b..0000000
--- a/tests_generated/test_ide_vscode-True/poetry.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[virtualenvs]
-in-project = true
diff --git a/tests_generated/test_ide_vscode-True/pyproject.toml b/tests_generated/test_ide_vscode-True/pyproject.toml
deleted file mode 100644
index 1a04604..0000000
--- a/tests_generated/test_ide_vscode-True/pyproject.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[tool.poetry]
-name = "test_ide_vscode-True"
-version = "0.1.0"
-description = "Algorand smart contracts"
-authors = ["None "]
-readme = "README.md"
-
-[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
-algokit-utils = "^2.0.1"
-python-dotenv = "^1.0.0"
-
-[tool.poetry.group.dev.dependencies]
-black = {extras = ["d"], version = "*"}
-pytest = "*"
-pytest-cov = "*"
-pip-audit = "*"
-
-[build-system]
-requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
-
-
-[tool.pytest.ini_options]
-pythonpath = ["smart_contracts", "tests"]
diff --git a/tests_generated/test_ide_vscode-True/smart_contracts/README.md b/tests_generated/test_ide_vscode-True/smart_contracts/README.md
deleted file mode 100644
index f765c95..0000000
--- a/tests_generated/test_ide_vscode-True/smart_contracts/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-## How to add new smart contracts?
-
-By the default the template creates a single `HelloWorld` contract under hello_world folder in the `smart_contracts` directory. To add a new contract:
-
-1. From the root of the project (`../`) execute `algokit generate smart-contract`. This will create a new starter smart contract and deployment configuration file under `{your_contract_name}` subfolder under `smart_contracts` directory.
-2. Each contract potentially has different creation parameters and deployment steps. Hence, you need to define your deployment logic in `deploy_config.py`file.
-3. `config.py` file will automatically build all contracts under `smart_contracts` directory. If you want to build specific contracts manually, modify the default code provided by the template in `config.py` file.
-
-> Please note, above is just a suggested convention tailored for the base configuration and structure of this template. Default code supplied by the template in `config.py` and `index.ts` (if using ts clients) files are tailored for the suggested convention. You are free to modify the structure and naming conventions as you see fit.
diff --git a/tests_generated/test_ide_vscode-True/smart_contracts/__init__.py b/tests_generated/test_ide_vscode-True/smart_contracts/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_ide_vscode-True/smart_contracts/__main__.py b/tests_generated/test_ide_vscode-True/smart_contracts/__main__.py
deleted file mode 100644
index 3ef8a27..0000000
--- a/tests_generated/test_ide_vscode-True/smart_contracts/__main__.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import logging
-import sys
-from pathlib import Path
-
-from dotenv import load_dotenv
-
-from smart_contracts.config import contracts
-from smart_contracts.helpers.build import build
-from smart_contracts.helpers.deploy import deploy
-
-logging.basicConfig(
- level=logging.DEBUG, format="%(asctime)s %(levelname)-10s: %(message)s"
-)
-logger = logging.getLogger(__name__)
-logger.info("Loading .env")
-load_dotenv()
-root_path = Path(__file__).parent
-
-
-def main(action: str) -> None:
- artifact_path = root_path / "artifacts"
- match action:
- case "build":
- for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
- case "deploy":
- for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
- if contract.deploy:
- deploy(app_spec_path, contract.deploy)
- case "all":
- for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
- if contract.deploy:
- deploy(app_spec_path, contract.deploy)
-
-
-if __name__ == "__main__":
- if len(sys.argv) > 1:
- main(sys.argv[1])
- else:
- main("all")
diff --git a/tests_generated/test_ide_vscode-True/smart_contracts/config.py b/tests_generated/test_ide_vscode-True/smart_contracts/config.py
deleted file mode 100644
index 8cefdd6..0000000
--- a/tests_generated/test_ide_vscode-True/smart_contracts/config.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import dataclasses
-import importlib
-from collections.abc import Callable
-from pathlib import Path
-
-from algokit_utils import Account, ApplicationSpecification
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
-
-
-@dataclasses.dataclass
-class SmartContract:
- app: Application
- deploy: Callable[
- [AlgodClient, IndexerClient, ApplicationSpecification, Account], None
- ] | None = None
-
-
-def import_contract(folder: Path) -> Application:
- """Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
-
-
-def import_deploy_if_exists(
- folder: Path,
-) -> (
- Callable[[AlgodClient, IndexerClient, ApplicationSpecification, Account], None]
- | None
-):
- """Imports the deploy function from a folder if it exists."""
- try:
- deploy_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.deploy_config"
- )
- return deploy_module.deploy
- except ImportError:
- return None
-
-
-def has_contract_file(directory: Path) -> bool:
- """Checks whether the directory contains contract.py file."""
- return (directory / "contract.py").exists()
-
-
-# define contracts to build and/or deploy
-base_dir = Path("smart_contracts")
-contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
- for folder in base_dir.iterdir()
- if folder.is_dir() and has_contract_file(folder)
-]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_ide_vscode-True/smart_contracts/hello_world/contract.py b/tests_generated/test_ide_vscode-True/smart_contracts/hello_world/contract.py
deleted file mode 100644
index 5ed8de0..0000000
--- a/tests_generated/test_ide_vscode-True/smart_contracts/hello_world/contract.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import beaker
-import pyteal as pt
-
-
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
diff --git a/tests_generated/test_ide_vscode-True/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_ide_vscode-True/smart_contracts/hello_world/deploy_config.py
deleted file mode 100644
index 4afdc60..0000000
--- a/tests_generated/test_ide_vscode-True/smart_contracts/hello_world/deploy_config.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import logging
-
-import algokit_utils
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-
-logger = logging.getLogger(__name__)
-
-
-# define deployment behaviour based on supplied app spec
-def deploy(
- algod_client: AlgodClient,
- indexer_client: IndexerClient,
- app_spec: algokit_utils.ApplicationSpecification,
- deployer: algokit_utils.Account,
-) -> None:
- from smart_contracts.artifacts.hello_world.client import (
- HelloWorldClient,
- )
-
- app_client = HelloWorldClient(
- algod_client,
- creator=deployer,
- indexer_client=indexer_client,
- )
- app_client.deploy(
- on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
- on_update=algokit_utils.OnUpdate.AppendApp,
- )
-
- name = "world"
- response = app_client.hello(name=name)
- logger.info(
- f"Called hello on {app_spec.contract.name} ({app_client.app_id}) "
- f"with name={name}, received: {response.return_value}"
- )
diff --git a/tests_generated/test_ide_vscode-True/smart_contracts/helpers/__init__.py b/tests_generated/test_ide_vscode-True/smart_contracts/helpers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_ide_vscode-True/smart_contracts/helpers/build.py b/tests_generated/test_ide_vscode-True/smart_contracts/helpers/build.py
deleted file mode 100644
index 201e5d6..0000000
--- a/tests_generated/test_ide_vscode-True/smart_contracts/helpers/build.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import logging
-import subprocess
-from pathlib import Path
-from shutil import rmtree
-
-import beaker
-
-logger = logging.getLogger(__name__)
-deployment_extension = "py"
-
-
-def build(output_dir: Path, app: beaker.Application) -> Path:
- output_dir = output_dir.resolve()
- if output_dir.exists():
- rmtree(output_dir)
- output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
-
- result = subprocess.run(
- [
- "algokit",
- "generate",
- "client",
- output_dir / "application.json",
- "--output",
- output_dir / f"client.{deployment_extension}",
- ],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- text=True,
- )
- if result.returncode:
- if "No such command" in result.stdout:
- raise Exception(
- "Could not generate typed client, requires AlgoKit 1.1 or "
- "later. Please update AlgoKit"
- )
- else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
- return output_dir / "application.json"
diff --git a/tests_generated/test_ide_vscode-True/smart_contracts/helpers/deploy.py b/tests_generated/test_ide_vscode-True/smart_contracts/helpers/deploy.py
deleted file mode 100644
index 08367a3..0000000
--- a/tests_generated/test_ide_vscode-True/smart_contracts/helpers/deploy.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import logging
-from collections.abc import Callable
-from pathlib import Path
-
-from algokit_utils import (
- Account,
- ApplicationSpecification,
- EnsureBalanceParameters,
- ensure_funded,
- get_account,
- get_algod_client,
- get_indexer_client,
-)
-from algosdk.util import algos_to_microalgos
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-
-logger = logging.getLogger(__name__)
-
-
-def deploy(
- app_spec_path: Path,
- deploy_callback: Callable[
- [AlgodClient, IndexerClient, ApplicationSpecification, Account], None
- ],
- deployer_initial_funds: int = 2,
-) -> None:
- # get clients
- # by default client configuration is loaded from environment variables
- algod_client = get_algod_client()
- indexer_client = get_indexer_client()
-
- # get app spec
- app_spec = ApplicationSpecification.from_json(app_spec_path.read_text())
-
- # get deployer account by name
- deployer = get_account(algod_client, "DEPLOYER", fund_with_algos=0)
-
- minimum_funds_micro_algos = algos_to_microalgos(deployer_initial_funds)
- ensure_funded(
- algod_client,
- EnsureBalanceParameters(
- account_to_fund=deployer,
- min_spending_balance_micro_algos=minimum_funds_micro_algos,
- min_funding_increment_micro_algos=minimum_funds_micro_algos,
- ),
- )
-
- # use provided callback to deploy the app
- deploy_callback(algod_client, indexer_client, app_spec, deployer)
diff --git a/tests_generated/test_ide_vscode-True/tests/__init__.py b/tests_generated/test_ide_vscode-True/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_ide_vscode-True/tests/conftest.py b/tests_generated/test_ide_vscode-True/tests/conftest.py
deleted file mode 100644
index 06a89eb..0000000
--- a/tests_generated/test_ide_vscode-True/tests/conftest.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from pathlib import Path
-
-import pytest
-from algokit_utils import (
- get_algod_client,
- is_localnet,
-)
-from algosdk.v2client.algod import AlgodClient
-from dotenv import load_dotenv
-
-
-@pytest.fixture(autouse=True, scope="session")
-def environment_fixture() -> None:
- env_path = Path(__file__).parent.parent / ".env.localnet"
- load_dotenv(env_path)
-
-
-@pytest.fixture(scope="session")
-def algod_client() -> AlgodClient:
- client = get_algod_client()
-
- # you can remove this assertion to test on other networks,
- # included here to prevent accidentally running against other networks
- assert is_localnet(client)
- return client
diff --git a/tests_generated/test_ide_vscode-True/tests/hello_world_test.py b/tests_generated/test_ide_vscode-True/tests/hello_world_test.py
deleted file mode 100644
index 50fd332..0000000
--- a/tests_generated/test_ide_vscode-True/tests/hello_world_test.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
-from algosdk.v2client.algod import AlgodClient
-
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
-
-
-@pytest.fixture(scope="session")
-def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
- algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
- )
- client.create()
- return client
-
-
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
-
- assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_preset_name-production/.vscode/launch.json b/tests_generated/test_preset_name-production/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_preset_name-production/.vscode/launch.json
+++ b/tests_generated/test_preset_name-production/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_preset_name-production/.vscode/tasks.json b/tests_generated/test_preset_name-production/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_preset_name-production/.vscode/tasks.json
+++ b/tests_generated/test_preset_name-production/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_preset_name-production/README.md b/tests_generated/test_preset_name-production/README.md
index 3eec6b0..4975ce0 100644
--- a/tests_generated/test_preset_name-production/README.md
+++ b/tests_generated/test_preset_name-production/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -86,7 +93,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
diff --git a/tests_generated/test_preset_name-production/pyproject.toml b/tests_generated/test_preset_name-production/pyproject.toml
index e4ceb54..5e99561 100644
--- a/tests_generated/test_preset_name-production/pyproject.toml
+++ b/tests_generated/test_preset_name-production/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
diff --git a/tests_generated/test_preset_name-production/smart_contracts/__main__.py b/tests_generated/test_preset_name-production/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_preset_name-production/smart_contracts/__main__.py
+++ b/tests_generated/test_preset_name-production/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_preset_name-production/smart_contracts/config.py b/tests_generated/test_preset_name-production/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_preset_name-production/smart_contracts/config.py
+++ b/tests_generated/test_preset_name-production/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_preset_name-production/smart_contracts/hello_world/contract.py b/tests_generated/test_preset_name-production/smart_contracts/hello_world/contract.py
index bfda2ca..1b8fddb 100644
--- a/tests_generated/test_preset_name-production/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_preset_name-production/smart_contracts/hello_world/contract.py
@@ -1,26 +1,8 @@
-import beaker
-import pyteal as pt
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_preset_name-production/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_preset_name-production/smart_contracts/hello_world/deploy_config.py
index 7ed7ad6..9ab7336 100644
--- a/tests_generated/test_preset_name-production/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_preset_name-production/smart_contracts/hello_world/deploy_config.py
@@ -23,20 +23,10 @@ def deploy(
creator=deployer,
indexer_client=indexer_client,
)
- is_mainnet = algokit_utils.is_mainnet(algod_client)
app_client.deploy(
- on_schema_break=(
- algokit_utils.OnSchemaBreak.AppendApp
- if is_mainnet
- else algokit_utils.OnSchemaBreak.ReplaceApp
- ),
- on_update=algokit_utils.OnUpdate.AppendApp
- if is_mainnet
- else algokit_utils.OnUpdate.UpdateApp,
- allow_delete=not is_mainnet,
- allow_update=not is_mainnet,
+ on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
+ on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_preset_name-production/smart_contracts/helpers/build.py b/tests_generated/test_preset_name-production/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_preset_name-production/smart_contracts/helpers/build.py
+++ b/tests_generated/test_preset_name-production/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_preset_name-production/tests/hello_world_test.py b/tests_generated/test_preset_name-production/tests/hello_world_test.py
index 55f8333..f4262b9 100644
--- a/tests_generated/test_preset_name-production/tests/hello_world_test.py
+++ b/tests_generated/test_preset_name-production/tests/hello_world_test.py
@@ -1,34 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
- template_values={"UPDATABLE": 1, "DELETABLE": 1},
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_preset_name-starter/.vscode/launch.json b/tests_generated/test_preset_name-starter/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_preset_name-starter/.vscode/launch.json
+++ b/tests_generated/test_preset_name-starter/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_preset_name-starter/.vscode/tasks.json b/tests_generated/test_preset_name-starter/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_preset_name-starter/.vscode/tasks.json
+++ b/tests_generated/test_preset_name-starter/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_preset_name-starter/README.md b/tests_generated/test_preset_name-starter/README.md
index 623294b..cddf5ec 100644
--- a/tests_generated/test_preset_name-starter/README.md
+++ b/tests_generated/test_preset_name-starter/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -47,7 +54,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
diff --git a/tests_generated/test_preset_name-starter/pyproject.toml b/tests_generated/test_preset_name-starter/pyproject.toml
index 18c5fc2..ce31825 100644
--- a/tests_generated/test_preset_name-starter/pyproject.toml
+++ b/tests_generated/test_preset_name-starter/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
diff --git a/tests_generated/test_preset_name-starter/smart_contracts/__main__.py b/tests_generated/test_preset_name-starter/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_preset_name-starter/smart_contracts/__main__.py
+++ b/tests_generated/test_preset_name-starter/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_preset_name-starter/smart_contracts/config.py b/tests_generated/test_preset_name-starter/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_preset_name-starter/smart_contracts/config.py
+++ b/tests_generated/test_preset_name-starter/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_preset_name-starter/smart_contracts/hello_world/contract.py b/tests_generated/test_preset_name-starter/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_preset_name-starter/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_preset_name-starter/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_preset_name-starter/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_preset_name-starter/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_preset_name-starter/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_preset_name-starter/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_preset_name-starter/smart_contracts/helpers/build.py b/tests_generated/test_preset_name-starter/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_preset_name-starter/smart_contracts/helpers/build.py
+++ b/tests_generated/test_preset_name-starter/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_preset_name-starter/tests/hello_world_test.py b/tests_generated/test_preset_name-starter/tests/hello_world_test.py
index 50fd332..f4262b9 100644
--- a/tests_generated/test_preset_name-starter/tests/hello_world_test.py
+++ b/tests_generated/test_preset_name-starter/tests/hello_world_test.py
@@ -1,33 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_python_linter-flake8/.algokit.toml b/tests_generated/test_python_linter-flake8/.algokit.toml
deleted file mode 100644
index 77dfd4b..0000000
--- a/tests_generated/test_python_linter-flake8/.algokit.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[algokit]
-min_version = "v1.7.3"
-
-[deploy]
-command = "poetry run python -m smart_contracts deploy"
-environment_secrets = [
- "DEPLOYER_MNEMONIC",
-]
-
-[deploy.localnet]
-environment_secrets = []
-
-[generate.smart_contract]
-description = "Adds new smart contract to existing project"
-path = ".algokit/generators/create_contract"
diff --git a/tests_generated/test_python_linter-flake8/.copier-answers.yml b/tests_generated/test_python_linter-flake8/.copier-answers.yml
deleted file mode 100644
index 5c52f88..0000000
--- a/tests_generated/test_python_linter-flake8/.copier-answers.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
-_commit:
-_src_path:
-algod_port: 4001
-algod_server: http://localhost
-algod_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-author_email: None
-author_name: None
-contract_name: hello_world
-deployment_language: python
-ide_vscode: true
-indexer_port: 8980
-indexer_server: http://localhost
-indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
-project_name: test_python_linter-flake8
-use_python_black: true
-use_python_pytest: true
-
diff --git a/tests_generated/test_python_linter-flake8/.editorconfig b/tests_generated/test_python_linter-flake8/.editorconfig
deleted file mode 100644
index e2fda34..0000000
--- a/tests_generated/test_python_linter-flake8/.editorconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-root=true
-
-[*]
-indent_style = space
-indent_size = 2
-end_of_line = lf
-insert_final_newline = true
-
-[*.py]
-indent_size = 4
diff --git a/tests_generated/test_python_linter-flake8/.env.localnet.template b/tests_generated/test_python_linter-flake8/.env.localnet.template
deleted file mode 100644
index fcbf442..0000000
--- a/tests_generated/test_python_linter-flake8/.env.localnet.template
+++ /dev/null
@@ -1,7 +0,0 @@
-# this file should contain environment variables specific to algokit localnet
-ALGOD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-ALGOD_SERVER=http://localhost
-ALGOD_PORT=4001
-INDEXER_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-INDEXER_SERVER=http://localhost
-INDEXER_PORT=8980
diff --git a/tests_generated/test_python_linter-flake8/.env.template b/tests_generated/test_python_linter-flake8/.env.template
deleted file mode 100644
index 184b393..0000000
--- a/tests_generated/test_python_linter-flake8/.env.template
+++ /dev/null
@@ -1 +0,0 @@
-# this file should contain environment variables common to all environments/networks
diff --git a/tests_generated/test_python_linter-flake8/.env.testnet.template b/tests_generated/test_python_linter-flake8/.env.testnet.template
deleted file mode 100644
index eeea43d..0000000
--- a/tests_generated/test_python_linter-flake8/.env.testnet.template
+++ /dev/null
@@ -1,3 +0,0 @@
-# this file contains algorand network settings for interacting with testnet via algonode
-ALGOD_SERVER=https://testnet-api.algonode.cloud
-INDEXER_SERVER=https://testnet-idx.algonode.cloud
diff --git a/tests_generated/test_python_linter-flake8/.flake8 b/tests_generated/test_python_linter-flake8/.flake8
deleted file mode 100644
index eeaac64..0000000
--- a/tests_generated/test_python_linter-flake8/.flake8
+++ /dev/null
@@ -1,4 +0,0 @@
-[flake8]
-max-line-length = 88
-select = B,C,E,F,W,T4,B9
-extend-ignore = E203
diff --git a/tests_generated/test_python_linter-flake8/.gitattributes b/tests_generated/test_python_linter-flake8/.gitattributes
deleted file mode 100644
index 6313b56..0000000
--- a/tests_generated/test_python_linter-flake8/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-* text=auto eol=lf
diff --git a/tests_generated/test_python_linter-flake8/.gitignore b/tests_generated/test_python_linter-flake8/.gitignore
deleted file mode 100644
index 832924c..0000000
--- a/tests_generated/test_python_linter-flake8/.gitignore
+++ /dev/null
@@ -1,174 +0,0 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-cover/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-.pybuilder/
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-# For a library or package, you might want to ignore these files since the code is
-# intended to run in multiple environments; otherwise, check them in:
-# .python-version
-
-# pipenv
-# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-# However, in case of collaboration, if having platform-specific dependencies or dependencies
-# having no cross-platform support, pipenv may install dependencies that don't work, or not
-# install all needed dependencies.
-#Pipfile.lock
-
-# poetry
-# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
-# This is especially recommended for binary packages to ensure reproducibility, and is more
-# commonly ignored for libraries.
-# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
-#poetry.lock
-
-# pdm
-# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
-#pdm.lock
-# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
-# in version control.
-# https://pdm.fming.dev/#use-with-ide
-.pdm.toml
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-.env.*
-!.env.*.template
-!.env.template
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-# pytype static type analyzer
-.pytype/
-
-# Ruff (linter)
-.ruff_cache/
-
-# Cython debug symbols
-cython_debug/
-
-# PyCharm
-.idea
-!.idea/
-.idea/*
-!.idea/runConfigurations/
-
-# macOS
-.DS_Store
-
-# Received approval test files
-*.received.*
-
-# NPM
-node_modules
diff --git a/tests_generated/test_python_linter-flake8/.vscode/extensions.json b/tests_generated/test_python_linter-flake8/.vscode/extensions.json
deleted file mode 100644
index 484b7f7..0000000
--- a/tests_generated/test_python_linter-flake8/.vscode/extensions.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "recommendations": [
- "ms-python.python",
- "ms-python.flake8",
- "ms-python.black-formatter",
- "tamasfe.even-better-toml",
- "editorconfig.editorconfig"
- ]
-}
diff --git a/tests_generated/test_python_linter-flake8/.vscode/launch.json b/tests_generated/test_python_linter-flake8/.vscode/launch.json
deleted file mode 100644
index 8a39d26..0000000
--- a/tests_generated/test_python_linter-flake8/.vscode/launch.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Build & Deploy Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "cwd": "${workspaceFolder}",
- "preLaunchTask": "Start AlgoKit LocalNet",
- "envFile": "${workspaceFolder}/.env.localnet"
- },
- {
- "name": "Deploy Built Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "args": ["deploy"],
- "cwd": "${workspaceFolder}",
- "envFile": "${workspaceFolder}/.env.localnet"
- },
- {
- "name": "Build Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "args": ["build"],
- "cwd": "${workspaceFolder}"
- }
- ]
-}
diff --git a/tests_generated/test_python_linter-flake8/.vscode/settings.json b/tests_generated/test_python_linter-flake8/.vscode/settings.json
deleted file mode 100644
index 6444d86..0000000
--- a/tests_generated/test_python_linter-flake8/.vscode/settings.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- // General - see also /.editorconfig
- "editor.formatOnSave": true,
- "files.exclude": {
- "**/.git": true,
- "**/.DS_Store": true,
- "**/Thumbs.db": true,
- ".mypy_cache": true,
- ".pytest_cache": true,
- ".ruff_cache": true,
- "**/__pycache__": true,
- ".idea": true
- },
-
- // Python
- "python.analysis.extraPaths": ["${workspaceFolder}/smart_contracts"],
- "python.defaultInterpreterPath": "${workspaceFolder}/.venv",
- "[python]": {
- "editor.codeActionsOnSave": {
- "source.fixAll": true,
- // Prevent default import sorting from running; Ruff will sort imports for us anyway
- "source.organizeImports": false
- },
- "editor.defaultFormatter": "ms-python.black-formatter",
- },
- "black-formatter.args": ["--config=pyproject.toml"],
- "python.testing.pytestEnabled": true,
- "flake8.importStrategy": "fromEnvironment",
- "flake8.args": ["--config=.flake8"],
-
- // On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
- // so instead let's set it to RemoteSigned for VS Code terminal
- "terminal.integrated.shellArgs.windows": ["-ExecutionPolicy", "RemoteSigned"],
-}
diff --git a/tests_generated/test_python_linter-flake8/.vscode/tasks.json b/tests_generated/test_python_linter-flake8/.vscode/tasks.json
deleted file mode 100644
index fe7889a..0000000
--- a/tests_generated/test_python_linter-flake8/.vscode/tasks.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "version": "2.0.0",
- "tasks": [
- {
- "label": "Build Beaker application",
- "command": "${workspaceFolder}/.venv/bin/python",
- "windows": {
- "command": "${workspaceFolder}/.venv/Scripts/python.exe"
- },
- "args": ["-m", "smart_contracts", "build"],
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "group": {
- "kind": "build",
- "isDefault": true
- },
- "problemMatcher": []
- },
- {
- "label": "Build Beaker application (+ LocalNet)",
- "command": "${workspaceFolder}/.venv/bin/python",
- "windows": {
- "command": "${workspaceFolder}/.venv/Scripts/python.exe"
- },
- "args": ["-m", "smart_contracts", "build"],
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "dependsOn": "Start AlgoKit LocalNet",
- "problemMatcher": []
- },
- {
- "label": "Start AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "start"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- },
- {
- "label": "Stop AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "stop"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- },
- {
- "label": "Reset AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "reset"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- }
- ]
-}
diff --git a/tests_generated/test_python_linter-flake8/README.md b/tests_generated/test_python_linter-flake8/README.md
deleted file mode 100644
index 069f496..0000000
--- a/tests_generated/test_python_linter-flake8/README.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# test_python_linter-flake8
-
-This project has been generated using AlgoKit. See below for default getting started instructions.
-
-# Setup
-
-### Initial setup
-
-1. Clone this repository locally
-2. Install pre-requisites:
- - Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
- - Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
- - Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- - Copy `.env.template` to `.env`
- - Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
-3. Open the project and start debugging / developing via:
- - VS Code
- 1. Open the repository root in VS Code
- 2. Install recommended extensions
- 3. Hit F5 (or whatever you have debug mapped to) and it should start running with breakpoint debugging.
- > **Note**
- > If using Windows: Before running for the first time you will need to select the Python Interpreter.
- 1. Open the command palette (Ctrl/Cmd + Shift + P)
- 2. Search for `Python: Select Interpreter`
- 3. Select `./.venv/Scripts/python.exe`
- - JetBrains IDEs (please note, this setup is primarily optimized for PyCharm Community Edition)
- 1. Open the repository root in the IDE
- 2. It should automatically detect it's a Poetry project and set up a Python interpreter and virtual environment.
- 3. Hit Shift+F10|Ctrl+R (or whatever you have debug mapped to) and it should start running with breakpoint debugging. Please note, JetBrains IDEs on Windows have a known bug that in some cases may prevent executing shell scripts as pre-launch tasks, for workarounds refer to [JetBrains forums](https://youtrack.jetbrains.com/issue/IDEA-277486/Shell-script-configuration-cannot-run-as-before-launch-task).
- - Other
- 1. Open the repository root in your text editor of choice
- 2. In a terminal run `poetry shell`
- 3. Run `python -m smart_contracts` through your debugger of choice
-
-### Subsequently
-
-1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
-2. Follow step 3 above
-
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
-
-# Tools
-
-This project makes use of Python to build Algorand smart contracts. The following tools are in use:
-
-- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
-- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
-- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
-- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Flake8](https://flake8.pycqa.org/en/latest/): A Python linter for style guide enforcement.
-- [pytest](https://docs.pytest.org/): Automated testing.
-- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
-It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder.
-
diff --git a/tests_generated/test_python_linter-flake8/poetry.toml b/tests_generated/test_python_linter-flake8/poetry.toml
deleted file mode 100644
index ab1033b..0000000
--- a/tests_generated/test_python_linter-flake8/poetry.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[virtualenvs]
-in-project = true
diff --git a/tests_generated/test_python_linter-flake8/pyproject.toml b/tests_generated/test_python_linter-flake8/pyproject.toml
deleted file mode 100644
index 7668dea..0000000
--- a/tests_generated/test_python_linter-flake8/pyproject.toml
+++ /dev/null
@@ -1,27 +0,0 @@
-[tool.poetry]
-name = "test_python_linter-flake8"
-version = "0.1.0"
-description = "Algorand smart contracts"
-authors = ["None "]
-readme = "README.md"
-
-[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
-algokit-utils = "^2.0.1"
-python-dotenv = "^1.0.0"
-
-[tool.poetry.group.dev.dependencies]
-black = {extras = ["d"], version = "*"}
-flake8 = "*"
-pytest = "*"
-pytest-cov = "*"
-pip-audit = "*"
-
-[build-system]
-requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
-
-
-[tool.pytest.ini_options]
-pythonpath = ["smart_contracts", "tests"]
diff --git a/tests_generated/test_python_linter-flake8/smart_contracts/README.md b/tests_generated/test_python_linter-flake8/smart_contracts/README.md
deleted file mode 100644
index f765c95..0000000
--- a/tests_generated/test_python_linter-flake8/smart_contracts/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-## How to add new smart contracts?
-
-By the default the template creates a single `HelloWorld` contract under hello_world folder in the `smart_contracts` directory. To add a new contract:
-
-1. From the root of the project (`../`) execute `algokit generate smart-contract`. This will create a new starter smart contract and deployment configuration file under `{your_contract_name}` subfolder under `smart_contracts` directory.
-2. Each contract potentially has different creation parameters and deployment steps. Hence, you need to define your deployment logic in `deploy_config.py`file.
-3. `config.py` file will automatically build all contracts under `smart_contracts` directory. If you want to build specific contracts manually, modify the default code provided by the template in `config.py` file.
-
-> Please note, above is just a suggested convention tailored for the base configuration and structure of this template. Default code supplied by the template in `config.py` and `index.ts` (if using ts clients) files are tailored for the suggested convention. You are free to modify the structure and naming conventions as you see fit.
diff --git a/tests_generated/test_python_linter-flake8/smart_contracts/__init__.py b/tests_generated/test_python_linter-flake8/smart_contracts/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_python_linter-flake8/smart_contracts/__main__.py b/tests_generated/test_python_linter-flake8/smart_contracts/__main__.py
deleted file mode 100644
index 3ef8a27..0000000
--- a/tests_generated/test_python_linter-flake8/smart_contracts/__main__.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import logging
-import sys
-from pathlib import Path
-
-from dotenv import load_dotenv
-
-from smart_contracts.config import contracts
-from smart_contracts.helpers.build import build
-from smart_contracts.helpers.deploy import deploy
-
-logging.basicConfig(
- level=logging.DEBUG, format="%(asctime)s %(levelname)-10s: %(message)s"
-)
-logger = logging.getLogger(__name__)
-logger.info("Loading .env")
-load_dotenv()
-root_path = Path(__file__).parent
-
-
-def main(action: str) -> None:
- artifact_path = root_path / "artifacts"
- match action:
- case "build":
- for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
- case "deploy":
- for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
- if contract.deploy:
- deploy(app_spec_path, contract.deploy)
- case "all":
- for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
- if contract.deploy:
- deploy(app_spec_path, contract.deploy)
-
-
-if __name__ == "__main__":
- if len(sys.argv) > 1:
- main(sys.argv[1])
- else:
- main("all")
diff --git a/tests_generated/test_python_linter-flake8/smart_contracts/config.py b/tests_generated/test_python_linter-flake8/smart_contracts/config.py
deleted file mode 100644
index 8cefdd6..0000000
--- a/tests_generated/test_python_linter-flake8/smart_contracts/config.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import dataclasses
-import importlib
-from collections.abc import Callable
-from pathlib import Path
-
-from algokit_utils import Account, ApplicationSpecification
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
-
-
-@dataclasses.dataclass
-class SmartContract:
- app: Application
- deploy: Callable[
- [AlgodClient, IndexerClient, ApplicationSpecification, Account], None
- ] | None = None
-
-
-def import_contract(folder: Path) -> Application:
- """Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
-
-
-def import_deploy_if_exists(
- folder: Path,
-) -> (
- Callable[[AlgodClient, IndexerClient, ApplicationSpecification, Account], None]
- | None
-):
- """Imports the deploy function from a folder if it exists."""
- try:
- deploy_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.deploy_config"
- )
- return deploy_module.deploy
- except ImportError:
- return None
-
-
-def has_contract_file(directory: Path) -> bool:
- """Checks whether the directory contains contract.py file."""
- return (directory / "contract.py").exists()
-
-
-# define contracts to build and/or deploy
-base_dir = Path("smart_contracts")
-contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
- for folder in base_dir.iterdir()
- if folder.is_dir() and has_contract_file(folder)
-]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_python_linter-flake8/smart_contracts/hello_world/contract.py b/tests_generated/test_python_linter-flake8/smart_contracts/hello_world/contract.py
deleted file mode 100644
index 5ed8de0..0000000
--- a/tests_generated/test_python_linter-flake8/smart_contracts/hello_world/contract.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import beaker
-import pyteal as pt
-
-
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
diff --git a/tests_generated/test_python_linter-flake8/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_python_linter-flake8/smart_contracts/hello_world/deploy_config.py
deleted file mode 100644
index 4afdc60..0000000
--- a/tests_generated/test_python_linter-flake8/smart_contracts/hello_world/deploy_config.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import logging
-
-import algokit_utils
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-
-logger = logging.getLogger(__name__)
-
-
-# define deployment behaviour based on supplied app spec
-def deploy(
- algod_client: AlgodClient,
- indexer_client: IndexerClient,
- app_spec: algokit_utils.ApplicationSpecification,
- deployer: algokit_utils.Account,
-) -> None:
- from smart_contracts.artifacts.hello_world.client import (
- HelloWorldClient,
- )
-
- app_client = HelloWorldClient(
- algod_client,
- creator=deployer,
- indexer_client=indexer_client,
- )
- app_client.deploy(
- on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
- on_update=algokit_utils.OnUpdate.AppendApp,
- )
-
- name = "world"
- response = app_client.hello(name=name)
- logger.info(
- f"Called hello on {app_spec.contract.name} ({app_client.app_id}) "
- f"with name={name}, received: {response.return_value}"
- )
diff --git a/tests_generated/test_python_linter-flake8/smart_contracts/helpers/__init__.py b/tests_generated/test_python_linter-flake8/smart_contracts/helpers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_python_linter-flake8/smart_contracts/helpers/build.py b/tests_generated/test_python_linter-flake8/smart_contracts/helpers/build.py
deleted file mode 100644
index 201e5d6..0000000
--- a/tests_generated/test_python_linter-flake8/smart_contracts/helpers/build.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import logging
-import subprocess
-from pathlib import Path
-from shutil import rmtree
-
-import beaker
-
-logger = logging.getLogger(__name__)
-deployment_extension = "py"
-
-
-def build(output_dir: Path, app: beaker.Application) -> Path:
- output_dir = output_dir.resolve()
- if output_dir.exists():
- rmtree(output_dir)
- output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
-
- result = subprocess.run(
- [
- "algokit",
- "generate",
- "client",
- output_dir / "application.json",
- "--output",
- output_dir / f"client.{deployment_extension}",
- ],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- text=True,
- )
- if result.returncode:
- if "No such command" in result.stdout:
- raise Exception(
- "Could not generate typed client, requires AlgoKit 1.1 or "
- "later. Please update AlgoKit"
- )
- else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
- return output_dir / "application.json"
diff --git a/tests_generated/test_python_linter-flake8/smart_contracts/helpers/deploy.py b/tests_generated/test_python_linter-flake8/smart_contracts/helpers/deploy.py
deleted file mode 100644
index 08367a3..0000000
--- a/tests_generated/test_python_linter-flake8/smart_contracts/helpers/deploy.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import logging
-from collections.abc import Callable
-from pathlib import Path
-
-from algokit_utils import (
- Account,
- ApplicationSpecification,
- EnsureBalanceParameters,
- ensure_funded,
- get_account,
- get_algod_client,
- get_indexer_client,
-)
-from algosdk.util import algos_to_microalgos
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-
-logger = logging.getLogger(__name__)
-
-
-def deploy(
- app_spec_path: Path,
- deploy_callback: Callable[
- [AlgodClient, IndexerClient, ApplicationSpecification, Account], None
- ],
- deployer_initial_funds: int = 2,
-) -> None:
- # get clients
- # by default client configuration is loaded from environment variables
- algod_client = get_algod_client()
- indexer_client = get_indexer_client()
-
- # get app spec
- app_spec = ApplicationSpecification.from_json(app_spec_path.read_text())
-
- # get deployer account by name
- deployer = get_account(algod_client, "DEPLOYER", fund_with_algos=0)
-
- minimum_funds_micro_algos = algos_to_microalgos(deployer_initial_funds)
- ensure_funded(
- algod_client,
- EnsureBalanceParameters(
- account_to_fund=deployer,
- min_spending_balance_micro_algos=minimum_funds_micro_algos,
- min_funding_increment_micro_algos=minimum_funds_micro_algos,
- ),
- )
-
- # use provided callback to deploy the app
- deploy_callback(algod_client, indexer_client, app_spec, deployer)
diff --git a/tests_generated/test_python_linter-flake8/tests/__init__.py b/tests_generated/test_python_linter-flake8/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_python_linter-flake8/tests/conftest.py b/tests_generated/test_python_linter-flake8/tests/conftest.py
deleted file mode 100644
index 06a89eb..0000000
--- a/tests_generated/test_python_linter-flake8/tests/conftest.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from pathlib import Path
-
-import pytest
-from algokit_utils import (
- get_algod_client,
- is_localnet,
-)
-from algosdk.v2client.algod import AlgodClient
-from dotenv import load_dotenv
-
-
-@pytest.fixture(autouse=True, scope="session")
-def environment_fixture() -> None:
- env_path = Path(__file__).parent.parent / ".env.localnet"
- load_dotenv(env_path)
-
-
-@pytest.fixture(scope="session")
-def algod_client() -> AlgodClient:
- client = get_algod_client()
-
- # you can remove this assertion to test on other networks,
- # included here to prevent accidentally running against other networks
- assert is_localnet(client)
- return client
diff --git a/tests_generated/test_python_linter-flake8/tests/hello_world_test.py b/tests_generated/test_python_linter-flake8/tests/hello_world_test.py
deleted file mode 100644
index 50fd332..0000000
--- a/tests_generated/test_python_linter-flake8/tests/hello_world_test.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
-from algosdk.v2client.algod import AlgodClient
-
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
-
-
-@pytest.fixture(scope="session")
-def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
- algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
- )
- client.create()
- return client
-
-
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
-
- assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_python_linter-none/.algokit.toml b/tests_generated/test_python_linter-none/.algokit.toml
deleted file mode 100644
index 77dfd4b..0000000
--- a/tests_generated/test_python_linter-none/.algokit.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[algokit]
-min_version = "v1.7.3"
-
-[deploy]
-command = "poetry run python -m smart_contracts deploy"
-environment_secrets = [
- "DEPLOYER_MNEMONIC",
-]
-
-[deploy.localnet]
-environment_secrets = []
-
-[generate.smart_contract]
-description = "Adds new smart contract to existing project"
-path = ".algokit/generators/create_contract"
diff --git a/tests_generated/test_python_linter-none/.copier-answers.yml b/tests_generated/test_python_linter-none/.copier-answers.yml
deleted file mode 100644
index cd9381c..0000000
--- a/tests_generated/test_python_linter-none/.copier-answers.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
-_commit:
-_src_path:
-algod_port: 4001
-algod_server: http://localhost
-algod_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-author_email: None
-author_name: None
-contract_name: hello_world
-deployment_language: python
-ide_vscode: true
-indexer_port: 8980
-indexer_server: http://localhost
-indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
-project_name: test_python_linter-none
-use_python_black: true
-use_python_pytest: true
-
diff --git a/tests_generated/test_python_linter-none/.editorconfig b/tests_generated/test_python_linter-none/.editorconfig
deleted file mode 100644
index e2fda34..0000000
--- a/tests_generated/test_python_linter-none/.editorconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-root=true
-
-[*]
-indent_style = space
-indent_size = 2
-end_of_line = lf
-insert_final_newline = true
-
-[*.py]
-indent_size = 4
diff --git a/tests_generated/test_python_linter-none/.env.localnet.template b/tests_generated/test_python_linter-none/.env.localnet.template
deleted file mode 100644
index fcbf442..0000000
--- a/tests_generated/test_python_linter-none/.env.localnet.template
+++ /dev/null
@@ -1,7 +0,0 @@
-# this file should contain environment variables specific to algokit localnet
-ALGOD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-ALGOD_SERVER=http://localhost
-ALGOD_PORT=4001
-INDEXER_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-INDEXER_SERVER=http://localhost
-INDEXER_PORT=8980
diff --git a/tests_generated/test_python_linter-none/.env.template b/tests_generated/test_python_linter-none/.env.template
deleted file mode 100644
index 184b393..0000000
--- a/tests_generated/test_python_linter-none/.env.template
+++ /dev/null
@@ -1 +0,0 @@
-# this file should contain environment variables common to all environments/networks
diff --git a/tests_generated/test_python_linter-none/.env.testnet.template b/tests_generated/test_python_linter-none/.env.testnet.template
deleted file mode 100644
index eeea43d..0000000
--- a/tests_generated/test_python_linter-none/.env.testnet.template
+++ /dev/null
@@ -1,3 +0,0 @@
-# this file contains algorand network settings for interacting with testnet via algonode
-ALGOD_SERVER=https://testnet-api.algonode.cloud
-INDEXER_SERVER=https://testnet-idx.algonode.cloud
diff --git a/tests_generated/test_python_linter-none/.gitattributes b/tests_generated/test_python_linter-none/.gitattributes
deleted file mode 100644
index 6313b56..0000000
--- a/tests_generated/test_python_linter-none/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-* text=auto eol=lf
diff --git a/tests_generated/test_python_linter-none/.gitignore b/tests_generated/test_python_linter-none/.gitignore
deleted file mode 100644
index 832924c..0000000
--- a/tests_generated/test_python_linter-none/.gitignore
+++ /dev/null
@@ -1,174 +0,0 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-cover/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-.pybuilder/
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-# For a library or package, you might want to ignore these files since the code is
-# intended to run in multiple environments; otherwise, check them in:
-# .python-version
-
-# pipenv
-# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-# However, in case of collaboration, if having platform-specific dependencies or dependencies
-# having no cross-platform support, pipenv may install dependencies that don't work, or not
-# install all needed dependencies.
-#Pipfile.lock
-
-# poetry
-# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
-# This is especially recommended for binary packages to ensure reproducibility, and is more
-# commonly ignored for libraries.
-# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
-#poetry.lock
-
-# pdm
-# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
-#pdm.lock
-# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
-# in version control.
-# https://pdm.fming.dev/#use-with-ide
-.pdm.toml
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-.env.*
-!.env.*.template
-!.env.template
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-# pytype static type analyzer
-.pytype/
-
-# Ruff (linter)
-.ruff_cache/
-
-# Cython debug symbols
-cython_debug/
-
-# PyCharm
-.idea
-!.idea/
-.idea/*
-!.idea/runConfigurations/
-
-# macOS
-.DS_Store
-
-# Received approval test files
-*.received.*
-
-# NPM
-node_modules
diff --git a/tests_generated/test_python_linter-none/.vscode/extensions.json b/tests_generated/test_python_linter-none/.vscode/extensions.json
deleted file mode 100644
index 9a7b7f1..0000000
--- a/tests_generated/test_python_linter-none/.vscode/extensions.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "recommendations": [
- "ms-python.python",
- "ms-python.black-formatter",
- "tamasfe.even-better-toml",
- "editorconfig.editorconfig"
- ]
-}
diff --git a/tests_generated/test_python_linter-none/.vscode/launch.json b/tests_generated/test_python_linter-none/.vscode/launch.json
deleted file mode 100644
index 8a39d26..0000000
--- a/tests_generated/test_python_linter-none/.vscode/launch.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Build & Deploy Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "cwd": "${workspaceFolder}",
- "preLaunchTask": "Start AlgoKit LocalNet",
- "envFile": "${workspaceFolder}/.env.localnet"
- },
- {
- "name": "Deploy Built Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "args": ["deploy"],
- "cwd": "${workspaceFolder}",
- "envFile": "${workspaceFolder}/.env.localnet"
- },
- {
- "name": "Build Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "args": ["build"],
- "cwd": "${workspaceFolder}"
- }
- ]
-}
diff --git a/tests_generated/test_python_linter-none/.vscode/settings.json b/tests_generated/test_python_linter-none/.vscode/settings.json
deleted file mode 100644
index c2cc2b6..0000000
--- a/tests_generated/test_python_linter-none/.vscode/settings.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- // General - see also /.editorconfig
- "editor.formatOnSave": true,
- "files.exclude": {
- "**/.git": true,
- "**/.DS_Store": true,
- "**/Thumbs.db": true,
- ".mypy_cache": true,
- ".pytest_cache": true,
- ".ruff_cache": true,
- "**/__pycache__": true,
- ".idea": true
- },
-
- // Python
- "python.analysis.extraPaths": ["${workspaceFolder}/smart_contracts"],
- "python.defaultInterpreterPath": "${workspaceFolder}/.venv",
- "[python]": {
- "editor.codeActionsOnSave": {
- "source.fixAll": true,
- // Prevent default import sorting from running; Ruff will sort imports for us anyway
- "source.organizeImports": false
- },
- "editor.defaultFormatter": "ms-python.black-formatter",
- },
- "black-formatter.args": ["--config=pyproject.toml"],
- "python.testing.pytestEnabled": true,
-
- // On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
- // so instead let's set it to RemoteSigned for VS Code terminal
- "terminal.integrated.shellArgs.windows": ["-ExecutionPolicy", "RemoteSigned"],
-}
diff --git a/tests_generated/test_python_linter-none/.vscode/tasks.json b/tests_generated/test_python_linter-none/.vscode/tasks.json
deleted file mode 100644
index fe7889a..0000000
--- a/tests_generated/test_python_linter-none/.vscode/tasks.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "version": "2.0.0",
- "tasks": [
- {
- "label": "Build Beaker application",
- "command": "${workspaceFolder}/.venv/bin/python",
- "windows": {
- "command": "${workspaceFolder}/.venv/Scripts/python.exe"
- },
- "args": ["-m", "smart_contracts", "build"],
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "group": {
- "kind": "build",
- "isDefault": true
- },
- "problemMatcher": []
- },
- {
- "label": "Build Beaker application (+ LocalNet)",
- "command": "${workspaceFolder}/.venv/bin/python",
- "windows": {
- "command": "${workspaceFolder}/.venv/Scripts/python.exe"
- },
- "args": ["-m", "smart_contracts", "build"],
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "dependsOn": "Start AlgoKit LocalNet",
- "problemMatcher": []
- },
- {
- "label": "Start AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "start"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- },
- {
- "label": "Stop AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "stop"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- },
- {
- "label": "Reset AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "reset"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- }
- ]
-}
diff --git a/tests_generated/test_python_linter-none/README.md b/tests_generated/test_python_linter-none/README.md
deleted file mode 100644
index 505fab8..0000000
--- a/tests_generated/test_python_linter-none/README.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# test_python_linter-none
-
-This project has been generated using AlgoKit. See below for default getting started instructions.
-
-# Setup
-
-### Initial setup
-
-1. Clone this repository locally
-2. Install pre-requisites:
- - Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
- - Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
- - Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- - Copy `.env.template` to `.env`
- - Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
-3. Open the project and start debugging / developing via:
- - VS Code
- 1. Open the repository root in VS Code
- 2. Install recommended extensions
- 3. Hit F5 (or whatever you have debug mapped to) and it should start running with breakpoint debugging.
- > **Note**
- > If using Windows: Before running for the first time you will need to select the Python Interpreter.
- 1. Open the command palette (Ctrl/Cmd + Shift + P)
- 2. Search for `Python: Select Interpreter`
- 3. Select `./.venv/Scripts/python.exe`
- - JetBrains IDEs (please note, this setup is primarily optimized for PyCharm Community Edition)
- 1. Open the repository root in the IDE
- 2. It should automatically detect it's a Poetry project and set up a Python interpreter and virtual environment.
- 3. Hit Shift+F10|Ctrl+R (or whatever you have debug mapped to) and it should start running with breakpoint debugging. Please note, JetBrains IDEs on Windows have a known bug that in some cases may prevent executing shell scripts as pre-launch tasks, for workarounds refer to [JetBrains forums](https://youtrack.jetbrains.com/issue/IDEA-277486/Shell-script-configuration-cannot-run-as-before-launch-task).
- - Other
- 1. Open the repository root in your text editor of choice
- 2. In a terminal run `poetry shell`
- 3. Run `python -m smart_contracts` through your debugger of choice
-
-### Subsequently
-
-1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
-2. Follow step 3 above
-
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
-
-# Tools
-
-This project makes use of Python to build Algorand smart contracts. The following tools are in use:
-
-- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
-- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
-- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
-- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
-- [pytest](https://docs.pytest.org/): Automated testing.
-- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
-It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder.
-
diff --git a/tests_generated/test_python_linter-none/poetry.toml b/tests_generated/test_python_linter-none/poetry.toml
deleted file mode 100644
index ab1033b..0000000
--- a/tests_generated/test_python_linter-none/poetry.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[virtualenvs]
-in-project = true
diff --git a/tests_generated/test_python_linter-none/pyproject.toml b/tests_generated/test_python_linter-none/pyproject.toml
deleted file mode 100644
index 9a41e3c..0000000
--- a/tests_generated/test_python_linter-none/pyproject.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[tool.poetry]
-name = "test_python_linter-none"
-version = "0.1.0"
-description = "Algorand smart contracts"
-authors = ["None "]
-readme = "README.md"
-
-[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
-algokit-utils = "^2.0.1"
-python-dotenv = "^1.0.0"
-
-[tool.poetry.group.dev.dependencies]
-black = {extras = ["d"], version = "*"}
-pytest = "*"
-pytest-cov = "*"
-pip-audit = "*"
-
-[build-system]
-requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
-
-
-[tool.pytest.ini_options]
-pythonpath = ["smart_contracts", "tests"]
diff --git a/tests_generated/test_python_linter-none/smart_contracts/README.md b/tests_generated/test_python_linter-none/smart_contracts/README.md
deleted file mode 100644
index f765c95..0000000
--- a/tests_generated/test_python_linter-none/smart_contracts/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-## How to add new smart contracts?
-
-By the default the template creates a single `HelloWorld` contract under hello_world folder in the `smart_contracts` directory. To add a new contract:
-
-1. From the root of the project (`../`) execute `algokit generate smart-contract`. This will create a new starter smart contract and deployment configuration file under `{your_contract_name}` subfolder under `smart_contracts` directory.
-2. Each contract potentially has different creation parameters and deployment steps. Hence, you need to define your deployment logic in `deploy_config.py`file.
-3. `config.py` file will automatically build all contracts under `smart_contracts` directory. If you want to build specific contracts manually, modify the default code provided by the template in `config.py` file.
-
-> Please note, above is just a suggested convention tailored for the base configuration and structure of this template. Default code supplied by the template in `config.py` and `index.ts` (if using ts clients) files are tailored for the suggested convention. You are free to modify the structure and naming conventions as you see fit.
diff --git a/tests_generated/test_python_linter-none/smart_contracts/__init__.py b/tests_generated/test_python_linter-none/smart_contracts/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_python_linter-none/smart_contracts/__main__.py b/tests_generated/test_python_linter-none/smart_contracts/__main__.py
deleted file mode 100644
index 3ef8a27..0000000
--- a/tests_generated/test_python_linter-none/smart_contracts/__main__.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import logging
-import sys
-from pathlib import Path
-
-from dotenv import load_dotenv
-
-from smart_contracts.config import contracts
-from smart_contracts.helpers.build import build
-from smart_contracts.helpers.deploy import deploy
-
-logging.basicConfig(
- level=logging.DEBUG, format="%(asctime)s %(levelname)-10s: %(message)s"
-)
-logger = logging.getLogger(__name__)
-logger.info("Loading .env")
-load_dotenv()
-root_path = Path(__file__).parent
-
-
-def main(action: str) -> None:
- artifact_path = root_path / "artifacts"
- match action:
- case "build":
- for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
- case "deploy":
- for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
- if contract.deploy:
- deploy(app_spec_path, contract.deploy)
- case "all":
- for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
- if contract.deploy:
- deploy(app_spec_path, contract.deploy)
-
-
-if __name__ == "__main__":
- if len(sys.argv) > 1:
- main(sys.argv[1])
- else:
- main("all")
diff --git a/tests_generated/test_python_linter-none/smart_contracts/config.py b/tests_generated/test_python_linter-none/smart_contracts/config.py
deleted file mode 100644
index 8cefdd6..0000000
--- a/tests_generated/test_python_linter-none/smart_contracts/config.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import dataclasses
-import importlib
-from collections.abc import Callable
-from pathlib import Path
-
-from algokit_utils import Account, ApplicationSpecification
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
-
-
-@dataclasses.dataclass
-class SmartContract:
- app: Application
- deploy: Callable[
- [AlgodClient, IndexerClient, ApplicationSpecification, Account], None
- ] | None = None
-
-
-def import_contract(folder: Path) -> Application:
- """Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
-
-
-def import_deploy_if_exists(
- folder: Path,
-) -> (
- Callable[[AlgodClient, IndexerClient, ApplicationSpecification, Account], None]
- | None
-):
- """Imports the deploy function from a folder if it exists."""
- try:
- deploy_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.deploy_config"
- )
- return deploy_module.deploy
- except ImportError:
- return None
-
-
-def has_contract_file(directory: Path) -> bool:
- """Checks whether the directory contains contract.py file."""
- return (directory / "contract.py").exists()
-
-
-# define contracts to build and/or deploy
-base_dir = Path("smart_contracts")
-contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
- for folder in base_dir.iterdir()
- if folder.is_dir() and has_contract_file(folder)
-]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_python_linter-none/smart_contracts/hello_world/contract.py b/tests_generated/test_python_linter-none/smart_contracts/hello_world/contract.py
deleted file mode 100644
index 5ed8de0..0000000
--- a/tests_generated/test_python_linter-none/smart_contracts/hello_world/contract.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import beaker
-import pyteal as pt
-
-
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
diff --git a/tests_generated/test_python_linter-none/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_python_linter-none/smart_contracts/hello_world/deploy_config.py
deleted file mode 100644
index 4afdc60..0000000
--- a/tests_generated/test_python_linter-none/smart_contracts/hello_world/deploy_config.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import logging
-
-import algokit_utils
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-
-logger = logging.getLogger(__name__)
-
-
-# define deployment behaviour based on supplied app spec
-def deploy(
- algod_client: AlgodClient,
- indexer_client: IndexerClient,
- app_spec: algokit_utils.ApplicationSpecification,
- deployer: algokit_utils.Account,
-) -> None:
- from smart_contracts.artifacts.hello_world.client import (
- HelloWorldClient,
- )
-
- app_client = HelloWorldClient(
- algod_client,
- creator=deployer,
- indexer_client=indexer_client,
- )
- app_client.deploy(
- on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
- on_update=algokit_utils.OnUpdate.AppendApp,
- )
-
- name = "world"
- response = app_client.hello(name=name)
- logger.info(
- f"Called hello on {app_spec.contract.name} ({app_client.app_id}) "
- f"with name={name}, received: {response.return_value}"
- )
diff --git a/tests_generated/test_python_linter-none/smart_contracts/helpers/__init__.py b/tests_generated/test_python_linter-none/smart_contracts/helpers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_python_linter-none/smart_contracts/helpers/build.py b/tests_generated/test_python_linter-none/smart_contracts/helpers/build.py
deleted file mode 100644
index 201e5d6..0000000
--- a/tests_generated/test_python_linter-none/smart_contracts/helpers/build.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import logging
-import subprocess
-from pathlib import Path
-from shutil import rmtree
-
-import beaker
-
-logger = logging.getLogger(__name__)
-deployment_extension = "py"
-
-
-def build(output_dir: Path, app: beaker.Application) -> Path:
- output_dir = output_dir.resolve()
- if output_dir.exists():
- rmtree(output_dir)
- output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
-
- result = subprocess.run(
- [
- "algokit",
- "generate",
- "client",
- output_dir / "application.json",
- "--output",
- output_dir / f"client.{deployment_extension}",
- ],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- text=True,
- )
- if result.returncode:
- if "No such command" in result.stdout:
- raise Exception(
- "Could not generate typed client, requires AlgoKit 1.1 or "
- "later. Please update AlgoKit"
- )
- else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
- return output_dir / "application.json"
diff --git a/tests_generated/test_python_linter-none/smart_contracts/helpers/deploy.py b/tests_generated/test_python_linter-none/smart_contracts/helpers/deploy.py
deleted file mode 100644
index 08367a3..0000000
--- a/tests_generated/test_python_linter-none/smart_contracts/helpers/deploy.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import logging
-from collections.abc import Callable
-from pathlib import Path
-
-from algokit_utils import (
- Account,
- ApplicationSpecification,
- EnsureBalanceParameters,
- ensure_funded,
- get_account,
- get_algod_client,
- get_indexer_client,
-)
-from algosdk.util import algos_to_microalgos
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-
-logger = logging.getLogger(__name__)
-
-
-def deploy(
- app_spec_path: Path,
- deploy_callback: Callable[
- [AlgodClient, IndexerClient, ApplicationSpecification, Account], None
- ],
- deployer_initial_funds: int = 2,
-) -> None:
- # get clients
- # by default client configuration is loaded from environment variables
- algod_client = get_algod_client()
- indexer_client = get_indexer_client()
-
- # get app spec
- app_spec = ApplicationSpecification.from_json(app_spec_path.read_text())
-
- # get deployer account by name
- deployer = get_account(algod_client, "DEPLOYER", fund_with_algos=0)
-
- minimum_funds_micro_algos = algos_to_microalgos(deployer_initial_funds)
- ensure_funded(
- algod_client,
- EnsureBalanceParameters(
- account_to_fund=deployer,
- min_spending_balance_micro_algos=minimum_funds_micro_algos,
- min_funding_increment_micro_algos=minimum_funds_micro_algos,
- ),
- )
-
- # use provided callback to deploy the app
- deploy_callback(algod_client, indexer_client, app_spec, deployer)
diff --git a/tests_generated/test_python_linter-none/tests/__init__.py b/tests_generated/test_python_linter-none/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_python_linter-none/tests/conftest.py b/tests_generated/test_python_linter-none/tests/conftest.py
deleted file mode 100644
index 06a89eb..0000000
--- a/tests_generated/test_python_linter-none/tests/conftest.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from pathlib import Path
-
-import pytest
-from algokit_utils import (
- get_algod_client,
- is_localnet,
-)
-from algosdk.v2client.algod import AlgodClient
-from dotenv import load_dotenv
-
-
-@pytest.fixture(autouse=True, scope="session")
-def environment_fixture() -> None:
- env_path = Path(__file__).parent.parent / ".env.localnet"
- load_dotenv(env_path)
-
-
-@pytest.fixture(scope="session")
-def algod_client() -> AlgodClient:
- client = get_algod_client()
-
- # you can remove this assertion to test on other networks,
- # included here to prevent accidentally running against other networks
- assert is_localnet(client)
- return client
diff --git a/tests_generated/test_python_linter-none/tests/hello_world_test.py b/tests_generated/test_python_linter-none/tests/hello_world_test.py
deleted file mode 100644
index 50fd332..0000000
--- a/tests_generated/test_python_linter-none/tests/hello_world_test.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
-from algosdk.v2client.algod import AlgodClient
-
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
-
-
-@pytest.fixture(scope="session")
-def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
- algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
- )
- client.create()
- return client
-
-
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
-
- assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_python_linter-ruff/.algokit.toml b/tests_generated/test_python_linter-ruff/.algokit.toml
deleted file mode 100644
index 77dfd4b..0000000
--- a/tests_generated/test_python_linter-ruff/.algokit.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[algokit]
-min_version = "v1.7.3"
-
-[deploy]
-command = "poetry run python -m smart_contracts deploy"
-environment_secrets = [
- "DEPLOYER_MNEMONIC",
-]
-
-[deploy.localnet]
-environment_secrets = []
-
-[generate.smart_contract]
-description = "Adds new smart contract to existing project"
-path = ".algokit/generators/create_contract"
diff --git a/tests_generated/test_python_linter-ruff/.copier-answers.yml b/tests_generated/test_python_linter-ruff/.copier-answers.yml
deleted file mode 100644
index 7681572..0000000
--- a/tests_generated/test_python_linter-ruff/.copier-answers.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
-_commit:
-_src_path:
-algod_port: 4001
-algod_server: http://localhost
-algod_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-author_email: None
-author_name: None
-contract_name: hello_world
-deployment_language: python
-ide_vscode: true
-indexer_port: 8980
-indexer_server: http://localhost
-indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
-project_name: test_python_linter-ruff
-use_python_black: true
-use_python_pytest: true
-
diff --git a/tests_generated/test_python_linter-ruff/.editorconfig b/tests_generated/test_python_linter-ruff/.editorconfig
deleted file mode 100644
index e2fda34..0000000
--- a/tests_generated/test_python_linter-ruff/.editorconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-root=true
-
-[*]
-indent_style = space
-indent_size = 2
-end_of_line = lf
-insert_final_newline = true
-
-[*.py]
-indent_size = 4
diff --git a/tests_generated/test_python_linter-ruff/.env.localnet.template b/tests_generated/test_python_linter-ruff/.env.localnet.template
deleted file mode 100644
index fcbf442..0000000
--- a/tests_generated/test_python_linter-ruff/.env.localnet.template
+++ /dev/null
@@ -1,7 +0,0 @@
-# this file should contain environment variables specific to algokit localnet
-ALGOD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-ALGOD_SERVER=http://localhost
-ALGOD_PORT=4001
-INDEXER_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-INDEXER_SERVER=http://localhost
-INDEXER_PORT=8980
diff --git a/tests_generated/test_python_linter-ruff/.env.template b/tests_generated/test_python_linter-ruff/.env.template
deleted file mode 100644
index 184b393..0000000
--- a/tests_generated/test_python_linter-ruff/.env.template
+++ /dev/null
@@ -1 +0,0 @@
-# this file should contain environment variables common to all environments/networks
diff --git a/tests_generated/test_python_linter-ruff/.env.testnet.template b/tests_generated/test_python_linter-ruff/.env.testnet.template
deleted file mode 100644
index eeea43d..0000000
--- a/tests_generated/test_python_linter-ruff/.env.testnet.template
+++ /dev/null
@@ -1,3 +0,0 @@
-# this file contains algorand network settings for interacting with testnet via algonode
-ALGOD_SERVER=https://testnet-api.algonode.cloud
-INDEXER_SERVER=https://testnet-idx.algonode.cloud
diff --git a/tests_generated/test_python_linter-ruff/.gitattributes b/tests_generated/test_python_linter-ruff/.gitattributes
deleted file mode 100644
index 6313b56..0000000
--- a/tests_generated/test_python_linter-ruff/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-* text=auto eol=lf
diff --git a/tests_generated/test_python_linter-ruff/.gitignore b/tests_generated/test_python_linter-ruff/.gitignore
deleted file mode 100644
index 832924c..0000000
--- a/tests_generated/test_python_linter-ruff/.gitignore
+++ /dev/null
@@ -1,174 +0,0 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-cover/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-.pybuilder/
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-# For a library or package, you might want to ignore these files since the code is
-# intended to run in multiple environments; otherwise, check them in:
-# .python-version
-
-# pipenv
-# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-# However, in case of collaboration, if having platform-specific dependencies or dependencies
-# having no cross-platform support, pipenv may install dependencies that don't work, or not
-# install all needed dependencies.
-#Pipfile.lock
-
-# poetry
-# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
-# This is especially recommended for binary packages to ensure reproducibility, and is more
-# commonly ignored for libraries.
-# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
-#poetry.lock
-
-# pdm
-# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
-#pdm.lock
-# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
-# in version control.
-# https://pdm.fming.dev/#use-with-ide
-.pdm.toml
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-.env.*
-!.env.*.template
-!.env.template
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-# pytype static type analyzer
-.pytype/
-
-# Ruff (linter)
-.ruff_cache/
-
-# Cython debug symbols
-cython_debug/
-
-# PyCharm
-.idea
-!.idea/
-.idea/*
-!.idea/runConfigurations/
-
-# macOS
-.DS_Store
-
-# Received approval test files
-*.received.*
-
-# NPM
-node_modules
diff --git a/tests_generated/test_python_linter-ruff/.vscode/extensions.json b/tests_generated/test_python_linter-ruff/.vscode/extensions.json
deleted file mode 100644
index a72f5e3..0000000
--- a/tests_generated/test_python_linter-ruff/.vscode/extensions.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "recommendations": [
- "ms-python.python",
- "charliermarsh.ruff",
- "ms-python.black-formatter",
- "tamasfe.even-better-toml",
- "editorconfig.editorconfig"
- ]
-}
diff --git a/tests_generated/test_python_linter-ruff/.vscode/launch.json b/tests_generated/test_python_linter-ruff/.vscode/launch.json
deleted file mode 100644
index 8a39d26..0000000
--- a/tests_generated/test_python_linter-ruff/.vscode/launch.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Build & Deploy Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "cwd": "${workspaceFolder}",
- "preLaunchTask": "Start AlgoKit LocalNet",
- "envFile": "${workspaceFolder}/.env.localnet"
- },
- {
- "name": "Deploy Built Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "args": ["deploy"],
- "cwd": "${workspaceFolder}",
- "envFile": "${workspaceFolder}/.env.localnet"
- },
- {
- "name": "Build Beaker application",
- "type": "python",
- "request": "launch",
- "module": "smart_contracts",
- "args": ["build"],
- "cwd": "${workspaceFolder}"
- }
- ]
-}
diff --git a/tests_generated/test_python_linter-ruff/.vscode/settings.json b/tests_generated/test_python_linter-ruff/.vscode/settings.json
deleted file mode 100644
index 8e4914a..0000000
--- a/tests_generated/test_python_linter-ruff/.vscode/settings.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- // General - see also /.editorconfig
- "editor.formatOnSave": true,
- "files.exclude": {
- "**/.git": true,
- "**/.DS_Store": true,
- "**/Thumbs.db": true,
- ".mypy_cache": true,
- ".pytest_cache": true,
- ".ruff_cache": true,
- "**/__pycache__": true,
- ".idea": true
- },
-
- // Python
- "python.analysis.extraPaths": ["${workspaceFolder}/smart_contracts"],
- "python.defaultInterpreterPath": "${workspaceFolder}/.venv",
- "[python]": {
- "editor.codeActionsOnSave": {
- "source.fixAll": true,
- // Prevent default import sorting from running; Ruff will sort imports for us anyway
- "source.organizeImports": false
- },
- "editor.defaultFormatter": "ms-python.black-formatter",
- },
- "black-formatter.args": ["--config=pyproject.toml"],
- "python.testing.pytestEnabled": true,
- "ruff.enable": true,
- "ruff.lint.run": "onSave",
- "ruff.lint.args": ["--config=pyproject.toml"],
- "ruff.importStrategy": "fromEnvironment",
- "ruff.fixAll": true, //lint and fix all files in workspace
- "ruff.organizeImports": true, //organize imports on save
- "ruff.codeAction.disableRuleComment": {
- "enable": true
- },
- "ruff.codeAction.fixViolation": {
- "enable": true
- },
-
- // On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
- // so instead let's set it to RemoteSigned for VS Code terminal
- "terminal.integrated.shellArgs.windows": ["-ExecutionPolicy", "RemoteSigned"],
-}
diff --git a/tests_generated/test_python_linter-ruff/.vscode/tasks.json b/tests_generated/test_python_linter-ruff/.vscode/tasks.json
deleted file mode 100644
index fe7889a..0000000
--- a/tests_generated/test_python_linter-ruff/.vscode/tasks.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "version": "2.0.0",
- "tasks": [
- {
- "label": "Build Beaker application",
- "command": "${workspaceFolder}/.venv/bin/python",
- "windows": {
- "command": "${workspaceFolder}/.venv/Scripts/python.exe"
- },
- "args": ["-m", "smart_contracts", "build"],
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "group": {
- "kind": "build",
- "isDefault": true
- },
- "problemMatcher": []
- },
- {
- "label": "Build Beaker application (+ LocalNet)",
- "command": "${workspaceFolder}/.venv/bin/python",
- "windows": {
- "command": "${workspaceFolder}/.venv/Scripts/python.exe"
- },
- "args": ["-m", "smart_contracts", "build"],
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "dependsOn": "Start AlgoKit LocalNet",
- "problemMatcher": []
- },
- {
- "label": "Start AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "start"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- },
- {
- "label": "Stop AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "stop"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- },
- {
- "label": "Reset AlgoKit LocalNet",
- "command": "algokit",
- "args": ["localnet", "reset"],
- "type": "shell",
- "options": {
- "cwd": "${workspaceFolder}"
- },
- "problemMatcher": []
- }
- ]
-}
diff --git a/tests_generated/test_python_linter-ruff/README.md b/tests_generated/test_python_linter-ruff/README.md
deleted file mode 100644
index cd8e366..0000000
--- a/tests_generated/test_python_linter-ruff/README.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# test_python_linter-ruff
-
-This project has been generated using AlgoKit. See below for default getting started instructions.
-
-# Setup
-
-### Initial setup
-
-1. Clone this repository locally
-2. Install pre-requisites:
- - Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
- - Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
- - Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- - Copy `.env.template` to `.env`
- - Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
-3. Open the project and start debugging / developing via:
- - VS Code
- 1. Open the repository root in VS Code
- 2. Install recommended extensions
- 3. Hit F5 (or whatever you have debug mapped to) and it should start running with breakpoint debugging.
- > **Note**
- > If using Windows: Before running for the first time you will need to select the Python Interpreter.
- 1. Open the command palette (Ctrl/Cmd + Shift + P)
- 2. Search for `Python: Select Interpreter`
- 3. Select `./.venv/Scripts/python.exe`
- - JetBrains IDEs (please note, this setup is primarily optimized for PyCharm Community Edition)
- 1. Open the repository root in the IDE
- 2. It should automatically detect it's a Poetry project and set up a Python interpreter and virtual environment.
- 3. Hit Shift+F10|Ctrl+R (or whatever you have debug mapped to) and it should start running with breakpoint debugging. Please note, JetBrains IDEs on Windows have a known bug that in some cases may prevent executing shell scripts as pre-launch tasks, for workarounds refer to [JetBrains forums](https://youtrack.jetbrains.com/issue/IDEA-277486/Shell-script-configuration-cannot-run-as-before-launch-task).
- - Other
- 1. Open the repository root in your text editor of choice
- 2. In a terminal run `poetry shell`
- 3. Run `python -m smart_contracts` through your debugger of choice
-
-### Subsequently
-
-1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
-2. Follow step 3 above
-
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
-
-# Tools
-
-This project makes use of Python to build Algorand smart contracts. The following tools are in use:
-
-- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
-- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
-- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
-- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
-
-- [pytest](https://docs.pytest.org/): Automated testing.
-- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
-It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder.
-
diff --git a/tests_generated/test_python_linter-ruff/poetry.toml b/tests_generated/test_python_linter-ruff/poetry.toml
deleted file mode 100644
index ab1033b..0000000
--- a/tests_generated/test_python_linter-ruff/poetry.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[virtualenvs]
-in-project = true
diff --git a/tests_generated/test_python_linter-ruff/pyproject.toml b/tests_generated/test_python_linter-ruff/pyproject.toml
deleted file mode 100644
index 952fca9..0000000
--- a/tests_generated/test_python_linter-ruff/pyproject.toml
+++ /dev/null
@@ -1,39 +0,0 @@
-[tool.poetry]
-name = "test_python_linter-ruff"
-version = "0.1.0"
-description = "Algorand smart contracts"
-authors = ["None "]
-readme = "README.md"
-
-[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
-algokit-utils = "^2.0.1"
-python-dotenv = "^1.0.0"
-
-[tool.poetry.group.dev.dependencies]
-black = {extras = ["d"], version = "*"}
-ruff = "^0.1.6"
-pytest = "*"
-pytest-cov = "*"
-pip-audit = "*"
-
-[build-system]
-requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
-
-[tool.ruff]
-line-length = 120
-select = ["E", "F", "ANN", "UP", "N", "C4", "B", "A", "YTT", "W", "FBT", "Q", "RUF", "I"]
-ignore = [
- "ANN101", # no type for self
- "ANN102", # no type for cls
-]
-unfixable = ["B", "RUF"]
-
-[tool.ruff.flake8-annotations]
-allow-star-arg-any = true
-suppress-none-returning = true
-
-[tool.pytest.ini_options]
-pythonpath = ["smart_contracts", "tests"]
diff --git a/tests_generated/test_python_linter-ruff/smart_contracts/README.md b/tests_generated/test_python_linter-ruff/smart_contracts/README.md
deleted file mode 100644
index f765c95..0000000
--- a/tests_generated/test_python_linter-ruff/smart_contracts/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-## How to add new smart contracts?
-
-By the default the template creates a single `HelloWorld` contract under hello_world folder in the `smart_contracts` directory. To add a new contract:
-
-1. From the root of the project (`../`) execute `algokit generate smart-contract`. This will create a new starter smart contract and deployment configuration file under `{your_contract_name}` subfolder under `smart_contracts` directory.
-2. Each contract potentially has different creation parameters and deployment steps. Hence, you need to define your deployment logic in `deploy_config.py`file.
-3. `config.py` file will automatically build all contracts under `smart_contracts` directory. If you want to build specific contracts manually, modify the default code provided by the template in `config.py` file.
-
-> Please note, above is just a suggested convention tailored for the base configuration and structure of this template. Default code supplied by the template in `config.py` and `index.ts` (if using ts clients) files are tailored for the suggested convention. You are free to modify the structure and naming conventions as you see fit.
diff --git a/tests_generated/test_python_linter-ruff/smart_contracts/__init__.py b/tests_generated/test_python_linter-ruff/smart_contracts/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_python_linter-ruff/smart_contracts/__main__.py b/tests_generated/test_python_linter-ruff/smart_contracts/__main__.py
deleted file mode 100644
index 3ef8a27..0000000
--- a/tests_generated/test_python_linter-ruff/smart_contracts/__main__.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import logging
-import sys
-from pathlib import Path
-
-from dotenv import load_dotenv
-
-from smart_contracts.config import contracts
-from smart_contracts.helpers.build import build
-from smart_contracts.helpers.deploy import deploy
-
-logging.basicConfig(
- level=logging.DEBUG, format="%(asctime)s %(levelname)-10s: %(message)s"
-)
-logger = logging.getLogger(__name__)
-logger.info("Loading .env")
-load_dotenv()
-root_path = Path(__file__).parent
-
-
-def main(action: str) -> None:
- artifact_path = root_path / "artifacts"
- match action:
- case "build":
- for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
- case "deploy":
- for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
- if contract.deploy:
- deploy(app_spec_path, contract.deploy)
- case "all":
- for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
- if contract.deploy:
- deploy(app_spec_path, contract.deploy)
-
-
-if __name__ == "__main__":
- if len(sys.argv) > 1:
- main(sys.argv[1])
- else:
- main("all")
diff --git a/tests_generated/test_python_linter-ruff/smart_contracts/config.py b/tests_generated/test_python_linter-ruff/smart_contracts/config.py
deleted file mode 100644
index 8cefdd6..0000000
--- a/tests_generated/test_python_linter-ruff/smart_contracts/config.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import dataclasses
-import importlib
-from collections.abc import Callable
-from pathlib import Path
-
-from algokit_utils import Account, ApplicationSpecification
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
-
-
-@dataclasses.dataclass
-class SmartContract:
- app: Application
- deploy: Callable[
- [AlgodClient, IndexerClient, ApplicationSpecification, Account], None
- ] | None = None
-
-
-def import_contract(folder: Path) -> Application:
- """Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
-
-
-def import_deploy_if_exists(
- folder: Path,
-) -> (
- Callable[[AlgodClient, IndexerClient, ApplicationSpecification, Account], None]
- | None
-):
- """Imports the deploy function from a folder if it exists."""
- try:
- deploy_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.deploy_config"
- )
- return deploy_module.deploy
- except ImportError:
- return None
-
-
-def has_contract_file(directory: Path) -> bool:
- """Checks whether the directory contains contract.py file."""
- return (directory / "contract.py").exists()
-
-
-# define contracts to build and/or deploy
-base_dir = Path("smart_contracts")
-contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
- for folder in base_dir.iterdir()
- if folder.is_dir() and has_contract_file(folder)
-]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_python_linter-ruff/smart_contracts/hello_world/contract.py b/tests_generated/test_python_linter-ruff/smart_contracts/hello_world/contract.py
deleted file mode 100644
index 5ed8de0..0000000
--- a/tests_generated/test_python_linter-ruff/smart_contracts/hello_world/contract.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import beaker
-import pyteal as pt
-
-
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
diff --git a/tests_generated/test_python_linter-ruff/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_python_linter-ruff/smart_contracts/hello_world/deploy_config.py
deleted file mode 100644
index 4afdc60..0000000
--- a/tests_generated/test_python_linter-ruff/smart_contracts/hello_world/deploy_config.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import logging
-
-import algokit_utils
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-
-logger = logging.getLogger(__name__)
-
-
-# define deployment behaviour based on supplied app spec
-def deploy(
- algod_client: AlgodClient,
- indexer_client: IndexerClient,
- app_spec: algokit_utils.ApplicationSpecification,
- deployer: algokit_utils.Account,
-) -> None:
- from smart_contracts.artifacts.hello_world.client import (
- HelloWorldClient,
- )
-
- app_client = HelloWorldClient(
- algod_client,
- creator=deployer,
- indexer_client=indexer_client,
- )
- app_client.deploy(
- on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
- on_update=algokit_utils.OnUpdate.AppendApp,
- )
-
- name = "world"
- response = app_client.hello(name=name)
- logger.info(
- f"Called hello on {app_spec.contract.name} ({app_client.app_id}) "
- f"with name={name}, received: {response.return_value}"
- )
diff --git a/tests_generated/test_python_linter-ruff/smart_contracts/helpers/__init__.py b/tests_generated/test_python_linter-ruff/smart_contracts/helpers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_python_linter-ruff/smart_contracts/helpers/build.py b/tests_generated/test_python_linter-ruff/smart_contracts/helpers/build.py
deleted file mode 100644
index 201e5d6..0000000
--- a/tests_generated/test_python_linter-ruff/smart_contracts/helpers/build.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import logging
-import subprocess
-from pathlib import Path
-from shutil import rmtree
-
-import beaker
-
-logger = logging.getLogger(__name__)
-deployment_extension = "py"
-
-
-def build(output_dir: Path, app: beaker.Application) -> Path:
- output_dir = output_dir.resolve()
- if output_dir.exists():
- rmtree(output_dir)
- output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
-
- result = subprocess.run(
- [
- "algokit",
- "generate",
- "client",
- output_dir / "application.json",
- "--output",
- output_dir / f"client.{deployment_extension}",
- ],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- text=True,
- )
- if result.returncode:
- if "No such command" in result.stdout:
- raise Exception(
- "Could not generate typed client, requires AlgoKit 1.1 or "
- "later. Please update AlgoKit"
- )
- else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
- return output_dir / "application.json"
diff --git a/tests_generated/test_python_linter-ruff/smart_contracts/helpers/deploy.py b/tests_generated/test_python_linter-ruff/smart_contracts/helpers/deploy.py
deleted file mode 100644
index 08367a3..0000000
--- a/tests_generated/test_python_linter-ruff/smart_contracts/helpers/deploy.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import logging
-from collections.abc import Callable
-from pathlib import Path
-
-from algokit_utils import (
- Account,
- ApplicationSpecification,
- EnsureBalanceParameters,
- ensure_funded,
- get_account,
- get_algod_client,
- get_indexer_client,
-)
-from algosdk.util import algos_to_microalgos
-from algosdk.v2client.algod import AlgodClient
-from algosdk.v2client.indexer import IndexerClient
-
-logger = logging.getLogger(__name__)
-
-
-def deploy(
- app_spec_path: Path,
- deploy_callback: Callable[
- [AlgodClient, IndexerClient, ApplicationSpecification, Account], None
- ],
- deployer_initial_funds: int = 2,
-) -> None:
- # get clients
- # by default client configuration is loaded from environment variables
- algod_client = get_algod_client()
- indexer_client = get_indexer_client()
-
- # get app spec
- app_spec = ApplicationSpecification.from_json(app_spec_path.read_text())
-
- # get deployer account by name
- deployer = get_account(algod_client, "DEPLOYER", fund_with_algos=0)
-
- minimum_funds_micro_algos = algos_to_microalgos(deployer_initial_funds)
- ensure_funded(
- algod_client,
- EnsureBalanceParameters(
- account_to_fund=deployer,
- min_spending_balance_micro_algos=minimum_funds_micro_algos,
- min_funding_increment_micro_algos=minimum_funds_micro_algos,
- ),
- )
-
- # use provided callback to deploy the app
- deploy_callback(algod_client, indexer_client, app_spec, deployer)
diff --git a/tests_generated/test_python_linter-ruff/tests/__init__.py b/tests_generated/test_python_linter-ruff/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests_generated/test_python_linter-ruff/tests/conftest.py b/tests_generated/test_python_linter-ruff/tests/conftest.py
deleted file mode 100644
index 06a89eb..0000000
--- a/tests_generated/test_python_linter-ruff/tests/conftest.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from pathlib import Path
-
-import pytest
-from algokit_utils import (
- get_algod_client,
- is_localnet,
-)
-from algosdk.v2client.algod import AlgodClient
-from dotenv import load_dotenv
-
-
-@pytest.fixture(autouse=True, scope="session")
-def environment_fixture() -> None:
- env_path = Path(__file__).parent.parent / ".env.localnet"
- load_dotenv(env_path)
-
-
-@pytest.fixture(scope="session")
-def algod_client() -> AlgodClient:
- client = get_algod_client()
-
- # you can remove this assertion to test on other networks,
- # included here to prevent accidentally running against other networks
- assert is_localnet(client)
- return client
diff --git a/tests_generated/test_python_linter-ruff/tests/hello_world_test.py b/tests_generated/test_python_linter-ruff/tests/hello_world_test.py
deleted file mode 100644
index 50fd332..0000000
--- a/tests_generated/test_python_linter-ruff/tests/hello_world_test.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
-from algosdk.v2client.algod import AlgodClient
-
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
-
-
-@pytest.fixture(scope="session")
-def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
- algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
- )
- client.create()
- return client
-
-
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
-
- assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2 b/tests_generated/test_smart_contract_generator_default_production_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
index 01e5881..83b938b 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
@@ -1,30 +1,8 @@
-import beaker
-import pyteal as pt
-{% if preset_name == 'starter' %}
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("{{ contract_name }}")
-{% elif preset_name == 'production' -%}
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
-app = beaker.Application("{{ contract_name }}")
-
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-{% endif %}
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class {{ contract_name.split('_')|map('capitalize')|join }}(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy_config.py.j2 b/tests_generated/test_smart_contract_generator_default_production_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy_config.py.j2
index bb169ac..9ab7336 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy_config.py.j2
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy_config.py.j2
@@ -14,38 +14,19 @@ def deploy(
app_spec: algokit_utils.ApplicationSpecification,
deployer: algokit_utils.Account,
) -> None:
- from smart_contracts.artifacts.{{ contract_name }}.client import (
- {{ contract_name.split('_')|map('capitalize')|join }}Client,
+ from smart_contracts.artifacts.hello_world.client import (
+ HelloWorldClient,
)
- app_client = {{ contract_name.split('_')|map('capitalize')|join }}Client(
+ app_client = HelloWorldClient(
algod_client,
creator=deployer,
indexer_client=indexer_client,
)
-
-
- {%- if preset_name == 'starter' %}
app_client.deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
- {%- elif preset_name == 'production' %}
- is_mainnet = algokit_utils.is_mainnet(algod_client)
- app_client.deploy(
- on_schema_break=(
- algokit_utils.OnSchemaBreak.AppendApp
- if is_mainnet
- else algokit_utils.OnSchemaBreak.ReplaceApp
- ),
- on_update=algokit_utils.OnUpdate.AppendApp
- if is_mainnet
- else algokit_utils.OnUpdate.UpdateApp,
- allow_delete=not is_mainnet,
- allow_update=not is_mainnet,
- )
- {%- endif %}
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/.copier-answers.yml b/tests_generated/test_smart_contract_generator_default_production_preset_python/.copier-answers.yml
index a8e008f..b767dbb 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/.copier-answers.yml
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/.copier-answers.yml
@@ -12,7 +12,6 @@ ide_vscode: true
indexer_port: 8980
indexer_server: http://localhost
indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: production
project_name: test_smart_contract_generator_default_production_preset_python
python_linter: ruff
use_dispenser: false
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/.github/workflows/cd.yaml b/tests_generated/test_smart_contract_generator_default_production_preset_python/.github/workflows/cd.yaml
index cf31cca..3e0fd45 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/.github/workflows/cd.yaml
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/.github/workflows/cd.yaml
@@ -23,10 +23,10 @@ jobs:
- name: Install poetry
run: pipx install poetry
- - name: Set up Python 3.10
+ - name: Set up Python 3.12
uses: actions/setup-python@v4
with:
- python-version: '3.10'
+ python-version: '3.12'
cache: 'poetry'
- name: Install algokit
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/.github/workflows/checks.yaml b/tests_generated/test_smart_contract_generator_default_production_preset_python/.github/workflows/checks.yaml
index c03719d..f6d0102 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/.github/workflows/checks.yaml
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/.github/workflows/checks.yaml
@@ -13,10 +13,10 @@ jobs:
- name: Install poetry
run: pipx install poetry
- - name: Set up Python 3.10
+ - name: Set up Python 3.12
uses: actions/setup-python@v4
with:
- python-version: '3.10'
+ python-version: '3.12'
cache: 'poetry'
- name: Install algokit
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/.vscode/launch.json b/tests_generated/test_smart_contract_generator_default_production_preset_python/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/.vscode/launch.json
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/.vscode/tasks.json b/tests_generated/test_smart_contract_generator_default_production_preset_python/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/.vscode/tasks.json
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/README.md b/tests_generated/test_smart_contract_generator_default_production_preset_python/README.md
index d8adb51..7d4f687 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/README.md
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -86,7 +93,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/pyproject.toml b/tests_generated/test_smart_contract_generator_default_production_preset_python/pyproject.toml
index 4898afb..89a9a22 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/pyproject.toml
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
@@ -42,7 +42,7 @@ pythonpath = ["smart_contracts", "tests"]
[tool.mypy]
files = "smart_contracts/"
-python_version = "3.10"
+python_version = "3.12"
check_untyped_defs = true
warn_redundant_casts = true
warn_unused_ignores = true
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/__main__.py b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/__main__.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/config.py b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/config.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/cool_contract/contract.py b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/cool_contract/contract.py
index b82e618..76d1be4 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/cool_contract/contract.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/cool_contract/contract.py
@@ -1,26 +1,8 @@
-import beaker
-import pyteal as pt
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("cool_contract")
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class CoolContract(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/cool_contract/deploy_config.py b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/cool_contract/deploy_config.py
index 964de9a..9ab7336 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/cool_contract/deploy_config.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/cool_contract/deploy_config.py
@@ -14,29 +14,19 @@ def deploy(
app_spec: algokit_utils.ApplicationSpecification,
deployer: algokit_utils.Account,
) -> None:
- from smart_contracts.artifacts.cool_contract.client import (
- CoolContractClient,
+ from smart_contracts.artifacts.hello_world.client import (
+ HelloWorldClient,
)
- app_client = CoolContractClient(
+ app_client = HelloWorldClient(
algod_client,
creator=deployer,
indexer_client=indexer_client,
)
- is_mainnet = algokit_utils.is_mainnet(algod_client)
app_client.deploy(
- on_schema_break=(
- algokit_utils.OnSchemaBreak.AppendApp
- if is_mainnet
- else algokit_utils.OnSchemaBreak.ReplaceApp
- ),
- on_update=algokit_utils.OnUpdate.AppendApp
- if is_mainnet
- else algokit_utils.OnUpdate.UpdateApp,
- allow_delete=not is_mainnet,
- allow_update=not is_mainnet,
+ on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
+ on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/hello_world/contract.py b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/hello_world/contract.py
index bfda2ca..1b8fddb 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/hello_world/contract.py
@@ -1,26 +1,8 @@
-import beaker
-import pyteal as pt
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/hello_world/deploy_config.py
index 7ed7ad6..9ab7336 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/hello_world/deploy_config.py
@@ -23,20 +23,10 @@ def deploy(
creator=deployer,
indexer_client=indexer_client,
)
- is_mainnet = algokit_utils.is_mainnet(algod_client)
app_client.deploy(
- on_schema_break=(
- algokit_utils.OnSchemaBreak.AppendApp
- if is_mainnet
- else algokit_utils.OnSchemaBreak.ReplaceApp
- ),
- on_update=algokit_utils.OnUpdate.AppendApp
- if is_mainnet
- else algokit_utils.OnUpdate.UpdateApp,
- allow_delete=not is_mainnet,
- allow_update=not is_mainnet,
+ on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
+ on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/helpers/build.py b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/helpers/build.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_python/tests/hello_world_test.py b/tests_generated/test_smart_contract_generator_default_production_preset_python/tests/hello_world_test.py
index 55f8333..f4262b9 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_python/tests/hello_world_test.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_python/tests/hello_world_test.py
@@ -1,34 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
- template_values={"UPDATABLE": 1, "DELETABLE": 1},
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2 b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
index 01e5881..83b938b 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
@@ -1,30 +1,8 @@
-import beaker
-import pyteal as pt
-{% if preset_name == 'starter' %}
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("{{ contract_name }}")
-{% elif preset_name == 'production' -%}
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
-app = beaker.Application("{{ contract_name }}")
-
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-{% endif %}
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class {{ contract_name.split('_')|map('capitalize')|join }}(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy-config.ts.j2 b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy-config.ts.j2
index 325fb24..c8b69ba 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy-config.ts.j2
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy-config.ts.j2
@@ -1,9 +1,9 @@
import * as algokit from '@algorandfoundation/algokit-utils'
-import { {{ contract_name.split('_')|map('capitalize')|join }}Client } from '../artifacts/{{ contract_name }}/client'
+import { HelloWorldClient } from '../artifacts/hello_world/client'
// Below is a showcase of various deployment options you can use in TypeScript Client
export async function deploy() {
- console.log('=== Deploying {{ contract_name.split('_')|map('capitalize')|join }} ===')
+ console.log('=== Deploying HelloWorld ===')
const algod = algokit.getAlgoClient()
const indexer = algokit.getAlgoIndexerClient()
@@ -16,7 +16,7 @@ export async function deploy() {
},
algod,
)
- const appClient = new {{ contract_name.split('_')|map('capitalize')|join }}Client(
+ const appClient = new HelloWorldClient(
{
resolveBy: 'creatorAndName',
findExistingUsing: indexer,
@@ -26,20 +26,11 @@ export async function deploy() {
algod,
)
- {%- if preset_name == 'starter' %}
const app = await appClient.deploy({
onSchemaBreak: 'append',
onUpdate: 'append',
})
- {% elif preset_name == 'production' %}
- const isMainNet = await algokit.isMainNet(algod)
- const app = await appClient.deploy({
- allowDelete: !isMainNet,
- allowUpdate: !isMainNet,
- onSchemaBreak: isMainNet ? 'append' : 'replace',
- onUpdate: isMainNet ? 'append' : 'update',
- })
- {% endif %}
+
// If app was just created fund the app account
if (['create', 'replace'].includes(app.operationPerformed)) {
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.copier-answers.yml b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.copier-answers.yml
index 803705b..bb502cf 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.copier-answers.yml
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.copier-answers.yml
@@ -12,7 +12,6 @@ ide_vscode: true
indexer_port: 8980
indexer_server: http://localhost
indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: production
project_name: test_smart_contract_generator_default_production_preset_typescript
python_linter: ruff
use_dispenser: false
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.github/workflows/cd.yaml b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.github/workflows/cd.yaml
index cf31cca..3e0fd45 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.github/workflows/cd.yaml
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.github/workflows/cd.yaml
@@ -23,10 +23,10 @@ jobs:
- name: Install poetry
run: pipx install poetry
- - name: Set up Python 3.10
+ - name: Set up Python 3.12
uses: actions/setup-python@v4
with:
- python-version: '3.10'
+ python-version: '3.12'
cache: 'poetry'
- name: Install algokit
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.github/workflows/checks.yaml b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.github/workflows/checks.yaml
index 92be59e..eea57bf 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.github/workflows/checks.yaml
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.github/workflows/checks.yaml
@@ -13,10 +13,10 @@ jobs:
- name: Install poetry
run: pipx install poetry
- - name: Set up Python 3.10
+ - name: Set up Python 3.12
uses: actions/setup-python@v4
with:
- python-version: '3.10'
+ python-version: '3.12'
cache: 'poetry'
- name: Install algokit
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.vscode/launch.json b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.vscode/launch.json
index 4ccd8e1..b5c1fb6 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.vscode/launch.json
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
@@ -10,11 +10,11 @@
"cwd": "${workspaceFolder}/smart_contracts",
"console": "integratedTerminal",
"skipFiles": ["/**", "node_modules/**"],
- "preLaunchTask": "Build Beaker application (+ LocalNet)",
+ "preLaunchTask": "Build Puya application (+ LocalNet)",
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
@@ -25,7 +25,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.vscode/tasks.json b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.vscode/tasks.json
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/README.md b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/README.md
index 7b97567..ea273e5 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/README.md
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -87,7 +94,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-ts) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/pyproject.toml b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/pyproject.toml
index 615cf73..2135028 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/pyproject.toml
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
@@ -42,7 +42,7 @@ pythonpath = ["smart_contracts", "tests"]
[tool.mypy]
files = "smart_contracts/"
-python_version = "3.10"
+python_version = "3.12"
check_untyped_defs = true
warn_redundant_casts = true
warn_unused_ignores = true
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/__main__.py b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/__main__.py
index 0026e40..b91ab2e 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/__main__.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/__main__.py
@@ -21,8 +21,8 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
if __name__ == "__main__":
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/config.py b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/config.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/cool_contract/contract.py b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/cool_contract/contract.py
index b82e618..76d1be4 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/cool_contract/contract.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/cool_contract/contract.py
@@ -1,26 +1,8 @@
-import beaker
-import pyteal as pt
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("cool_contract")
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class CoolContract(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/cool_contract/deploy-config.ts b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/cool_contract/deploy-config.ts
index d51faf4..c8b69ba 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/cool_contract/deploy-config.ts
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/cool_contract/deploy-config.ts
@@ -1,9 +1,9 @@
import * as algokit from '@algorandfoundation/algokit-utils'
-import { CoolContractClient } from '../artifacts/cool_contract/client'
+import { HelloWorldClient } from '../artifacts/hello_world/client'
// Below is a showcase of various deployment options you can use in TypeScript Client
export async function deploy() {
- console.log('=== Deploying CoolContract ===')
+ console.log('=== Deploying HelloWorld ===')
const algod = algokit.getAlgoClient()
const indexer = algokit.getAlgoIndexerClient()
@@ -16,7 +16,7 @@ export async function deploy() {
},
algod,
)
- const appClient = new CoolContractClient(
+ const appClient = new HelloWorldClient(
{
resolveBy: 'creatorAndName',
findExistingUsing: indexer,
@@ -25,14 +25,12 @@ export async function deploy() {
},
algod,
)
- const isMainNet = await algokit.isMainNet(algod)
+
const app = await appClient.deploy({
- allowDelete: !isMainNet,
- allowUpdate: !isMainNet,
- onSchemaBreak: isMainNet ? 'append' : 'replace',
- onUpdate: isMainNet ? 'append' : 'update',
+ onSchemaBreak: 'append',
+ onUpdate: 'append',
})
-
+
// If app was just created fund the app account
if (['create', 'replace'].includes(app.operationPerformed)) {
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/hello_world/contract.py b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/hello_world/contract.py
index bfda2ca..1b8fddb 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/hello_world/contract.py
@@ -1,26 +1,8 @@
-import beaker
-import pyteal as pt
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/hello_world/deploy-config.ts b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/hello_world/deploy-config.ts
index dab537c..c8b69ba 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/hello_world/deploy-config.ts
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/hello_world/deploy-config.ts
@@ -25,14 +25,12 @@ export async function deploy() {
},
algod,
)
- const isMainNet = await algokit.isMainNet(algod)
+
const app = await appClient.deploy({
- allowDelete: !isMainNet,
- allowUpdate: !isMainNet,
- onSchemaBreak: isMainNet ? 'append' : 'replace',
- onUpdate: isMainNet ? 'append' : 'update',
+ onSchemaBreak: 'append',
+ onUpdate: 'append',
})
-
+
// If app was just created fund the app account
if (['create', 'replace'].includes(app.operationPerformed)) {
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/helpers/build.py b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/helpers/build.py
index 20d6d6d..67377d3 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/helpers/build.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "ts"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/tests/hello_world_test.py b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/tests/hello_world_test.py
index 55f8333..f4262b9 100644
--- a/tests_generated/test_smart_contract_generator_default_production_preset_typescript/tests/hello_world_test.py
+++ b/tests_generated/test_smart_contract_generator_default_production_preset_typescript/tests/hello_world_test.py
@@ -1,34 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
- template_values={"UPDATABLE": 1, "DELETABLE": 1},
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2 b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
index 01e5881..83b938b 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
@@ -1,30 +1,8 @@
-import beaker
-import pyteal as pt
-{% if preset_name == 'starter' %}
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("{{ contract_name }}")
-{% elif preset_name == 'production' -%}
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
-app = beaker.Application("{{ contract_name }}")
-
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-{% endif %}
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class {{ contract_name.split('_')|map('capitalize')|join }}(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy_config.py.j2 b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy_config.py.j2
index bb169ac..9ab7336 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy_config.py.j2
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy_config.py.j2
@@ -14,38 +14,19 @@ def deploy(
app_spec: algokit_utils.ApplicationSpecification,
deployer: algokit_utils.Account,
) -> None:
- from smart_contracts.artifacts.{{ contract_name }}.client import (
- {{ contract_name.split('_')|map('capitalize')|join }}Client,
+ from smart_contracts.artifacts.hello_world.client import (
+ HelloWorldClient,
)
- app_client = {{ contract_name.split('_')|map('capitalize')|join }}Client(
+ app_client = HelloWorldClient(
algod_client,
creator=deployer,
indexer_client=indexer_client,
)
-
-
- {%- if preset_name == 'starter' %}
app_client.deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
- {%- elif preset_name == 'production' %}
- is_mainnet = algokit_utils.is_mainnet(algod_client)
- app_client.deploy(
- on_schema_break=(
- algokit_utils.OnSchemaBreak.AppendApp
- if is_mainnet
- else algokit_utils.OnSchemaBreak.ReplaceApp
- ),
- on_update=algokit_utils.OnUpdate.AppendApp
- if is_mainnet
- else algokit_utils.OnUpdate.UpdateApp,
- allow_delete=not is_mainnet,
- allow_update=not is_mainnet,
- )
- {%- endif %}
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.copier-answers.yml b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.copier-answers.yml
index f7482ae..a6470a8 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.copier-answers.yml
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.copier-answers.yml
@@ -12,8 +12,13 @@ ide_vscode: true
indexer_port: 8980
indexer_server: http://localhost
indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
project_name: test_smart_contract_generator_default_starter_preset_python
+python_linter: ruff
+use_dispenser: false
+use_github_actions: true
+use_pre_commit: true
use_python_black: true
+use_python_mypy: true
+use_python_pip_audit: true
use_python_pytest: true
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.github/workflows/cd.yaml b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.github/workflows/cd.yaml
new file mode 100644
index 0000000..3e0fd45
--- /dev/null
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.github/workflows/cd.yaml
@@ -0,0 +1,50 @@
+name: Continuous Delivery of Smart Contract
+
+on:
+ push:
+ branches:
+ - main
+
+concurrency: release
+
+jobs:
+ ci-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
+
+ deploy-testnet:
+ runs-on: 'ubuntu-latest'
+ needs: ci-check
+ environment: Test
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Deploy to testnet
+ run: algokit deploy testnet
+ env:
+ # This is the account that becomes the creator of the contract.
+ # Since we are not using the optional dispenser account (via DISPENSER_MNEMONIC),
+ # it must also be funded with enough Algos to deploy and fund the smart contracts created
+ DEPLOYER_MNEMONIC: ${{ secrets.DEPLOYER_MNEMONIC }}
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.github/workflows/checks.yaml b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.github/workflows/checks.yaml
new file mode 100644
index 0000000..f6d0102
--- /dev/null
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.github/workflows/checks.yaml
@@ -0,0 +1,79 @@
+name: Check code base
+
+on:
+ workflow_call:
+
+jobs:
+ checks:
+ runs-on: 'ubuntu-latest'
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Start LocalNet
+ run: algokit localnet start
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Audit with pip-audit
+ run: |
+ # audit non dev dependencies, no exclusions
+ poetry export --without=dev > requirements.txt && poetry run pip-audit -r requirements.txt
+
+ # audit all dependencies, with exclusions.
+ # If a vulnerability is found in a dev dependency without an available fix,
+ # it can be temporarily ignored by adding --ignore-vuln e.g.
+ # --ignore-vuln "GHSA-hcpj-qp55-gfph" # GitPython vulnerability, dev only dependency
+ poetry run pip-audit
+
+ - name: Check formatting with Black
+ run: |
+ # stop the build if there are files that don't meet formatting requirements
+ poetry run black --check .
+
+ - name: Check linting with Ruff
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ poetry run ruff .
+
+ - name: Check types with mypy
+ run: poetry run mypy
+
+ - name: Run tests
+ shell: bash
+ run: |
+ set -o pipefail
+ poetry run pytest --junitxml=pytest-junit.xml
+
+ - name: Build smart contracts
+ run: poetry run python -m smart_contracts build
+
+ - name: Check output stability of the smart contracts
+ shell: bash
+ run: |
+ # Add untracked files as empty so they come up in diff
+ git add -N ./smart_contracts/artifacts
+ # Error out if there are any changes in teal after generating output
+ git diff --exit-code --minimal ./smart_contracts/artifacts || (echo "::error ::Smart contract artifacts have changed, ensure committed artifacts are up to date" && exit 1);
+
+ - name: Run deployer against LocalNet
+ run: poetry run python -m smart_contracts deploy
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.github/workflows/pr.yaml b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.github/workflows/pr.yaml
new file mode 100644
index 0000000..a80f784
--- /dev/null
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.github/workflows/pr.yaml
@@ -0,0 +1,8 @@
+name: Pull Request validation
+
+on: [pull_request]
+
+jobs:
+ pr-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.pre-commit-config.yaml b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.pre-commit-config.yaml
new file mode 100644
index 0000000..93bfff5
--- /dev/null
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.pre-commit-config.yaml
@@ -0,0 +1,38 @@
+repos:
+ - repo: local
+ hooks:
+
+ - id: black
+ name: black
+ description: "Black: The uncompromising Python code formatter"
+ entry: poetry run black
+ language: system
+ minimum_pre_commit_version: 2.9.2
+ require_serial: true
+ types_or: [ python, pyi ]
+
+
+ - id: ruff
+ name: ruff
+ description: "Run 'ruff' for extremely fast Python linting"
+ entry: poetry run ruff
+ language: system
+ types: [ python ]
+ args: [ --fix ]
+ require_serial: false
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '0'
+ files: '^(src|tests)/'
+
+
+ - id: mypy
+ name: mypy
+ description: '`mypy` will check Python types for correctness'
+ entry: poetry run mypy
+ language: system
+ types_or: [ python, pyi ]
+ require_serial: true
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '2.9.2'
+ files: '^(src|tests)/'
+
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/extensions.json b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/extensions.json
index 9a7b7f1..36d7c10 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/extensions.json
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/extensions.json
@@ -1,6 +1,8 @@
{
"recommendations": [
"ms-python.python",
+ "charliermarsh.ruff",
+ "matangover.mypy",
"ms-python.black-formatter",
"tamasfe.even-better-toml",
"editorconfig.editorconfig"
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/launch.json b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/launch.json
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/settings.json b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/settings.json
index c2cc2b6..0c2dfec 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/settings.json
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/settings.json
@@ -25,6 +25,23 @@
},
"black-formatter.args": ["--config=pyproject.toml"],
"python.testing.pytestEnabled": true,
+ "ruff.enable": true,
+ "ruff.lint.run": "onSave",
+ "ruff.lint.args": ["--config=pyproject.toml"],
+ "ruff.importStrategy": "fromEnvironment",
+ "ruff.fixAll": true, //lint and fix all files in workspace
+ "ruff.organizeImports": true, //organize imports on save
+ "ruff.codeAction.disableRuleComment": {
+ "enable": true
+ },
+ "ruff.codeAction.fixViolation": {
+ "enable": true
+ },
+ "python.analysis.typeCheckingMode": "off",
+ "mypy.configFile": "pyproject.toml",
+ // set to empty array to use config from project
+ "mypy.targets": [],
+ "mypy.runUsingActiveInterpreter": true,
// On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
// so instead let's set it to RemoteSigned for VS Code terminal
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/tasks.json b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/tasks.json
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/README.md b/tests_generated/test_smart_contract_generator_default_starter_preset_python/README.md
index 3ad2bb1..8acb8d7 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/README.md
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -39,7 +46,46 @@ This project has been generated using AlgoKit. See below for default getting sta
1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
2. Follow step 3 above
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
+> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.### Continuous Integration / Continuous Deployment (CI/CD)
+
+This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI/CD workflows, which are located in the [`.github/workflows`](./.github/workflows) folder.
+
+#### Setting up GitHub for CI/CD workflow and TestNet deployment
+
+ 1. Every time you have a change to your smart contract, and when you first initialize the project you need to [build the contract](#initial-setup) and then commit the `smart_contracts/artifacts` folder so the [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) tests pass
+ 2. Decide what values you want to use for the `allow_update`, `allow_delete` and the `on_schema_break`, `on_update` parameters specified in [`contract.py`](./smart_contracts/hello_world/contract.py).
+ When deploying to LocalNet these values are both set to allow update and replacement of the app for convenience. But for non-LocalNet networks
+ the defaults are more conservative.
+ These default values will allow the smart contract to be deployed initially, but will not allow the app to be updated or deleted if is changed and the build will instead fail.
+ To help you decide it may be helpful to read the [AlgoKit Utils app deployment documentation](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/app-deploy.md) or the [AlgoKit smart contract deployment architecture](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md#upgradeable-and-deletable-contracts).
+ 3. Create a [Github Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#creating-an-environment) named `Test`.
+ Note: If you have a private repository and don't have GitHub Enterprise then Environments won't work and you'll need to convert the GitHub Action to use a different approach. Ignore this step if you picked `Starter` preset.
+ 4. Create or obtain a mnemonic for an Algorand account for use on TestNet to deploy apps, referred to as the `DEPLOYER` account.
+ 5. Store the mnemonic as a [secret](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-secrets) `DEPLOYER_MNEMONIC`
+ in the Test environment created in step 3.
+ 6. The account used to deploy the smart contract will require enough funds to create the app, and also fund it. There are two approaches available here:
+ * Either, ensure the account is funded outside of CI/CD.
+ In Testnet, funds can be obtained by using the [Algorand TestNet dispenser](https://bank.testnet.algorand.network/) and we recommend provisioning 50 ALGOs.
+ * Or, fund the account as part of the CI/CD process by using a `DISPENSER_MNEMONIC` GitHub Environment secret to point to a separate `DISPENSER` account that you maintain ALGOs in (similarly, you need to provision ALGOs into this account using the [TestNet dispenser](https://bank.testnet.algorand.network/)).
+
+#### Continuous Integration
+
+For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions:
+ - Python dependencies are audited using [pip-audit](https://pypi.org/project/pip-audit/)
+ - Code formatting is checked using [Black](https://github.com/psf/black)
+ - Linting is checked using [Ruff](https://github.com/charliermarsh/ruff)
+ - Types are checked using [mypy](https://mypy-lang.org/)
+ - Python tests are executed using [pytest](https://docs.pytest.org/)
+ - Smart contract artifacts are built
+ - Smart contract artifacts are checked for [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md)
+ - Smart contract is deployed to a AlgoKit LocalNet instance
+
+#### Continuous Deployment
+
+For pushes to `main` branch, after the above checks pass, the following deployment actions are performed:
+ - The smart contract(s) are deployed to TestNet using [AlgoNode](https://algonode.io).
+
+> Please note deployment is also performed via `algokit deploy` command which can be invoked both via CI as seen on this project, or locally. For more information on how to use `algokit deploy` please see [AlgoKit documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/deploy.md).
# Tools
@@ -47,11 +93,14 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
+- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
+
+- [mypy](https://mypy-lang.org/): Static type checker.
- [pytest](https://docs.pytest.org/): Automated testing.
- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
+ - [pre-commit](https://pre-commit.com/): A framework for managing and maintaining multi-language pre-commit hooks, to enable pre-commit you need to run `pre-commit install` in the root of the repository. This will install the pre-commit hooks and run them against modified files when committing. If any of the hooks fail, the commit will be aborted. To run the hooks on all files, use `pre-commit run --all-files`.
It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder.
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/pyproject.toml b/tests_generated/test_smart_contract_generator_default_starter_preset_python/pyproject.toml
index 44aa551..52cd316 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/pyproject.toml
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/pyproject.toml
@@ -6,21 +6,45 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
+ruff = "^0.1.6"
+mypy = "*"
pytest = "*"
pytest-cov = "*"
pip-audit = "*"
+pre-commit = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
+[tool.ruff]
+line-length = 120
+select = ["E", "F", "ANN", "UP", "N", "C4", "B", "A", "YTT", "W", "FBT", "Q", "RUF", "I"]
+ignore = [
+ "ANN101", # no type for self
+ "ANN102", # no type for cls
+]
+unfixable = ["B", "RUF"]
+
+[tool.ruff.flake8-annotations]
+allow-star-arg-any = true
+suppress-none-returning = true
[tool.pytest.ini_options]
pythonpath = ["smart_contracts", "tests"]
+
+[tool.mypy]
+files = "smart_contracts/"
+python_version = "3.12"
+check_untyped_defs = true
+warn_redundant_casts = true
+warn_unused_ignores = true
+allow_untyped_defs = false
+strict_equality = true
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/__main__.py b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/__main__.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/config.py b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/config.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/cool_contract/contract.py b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/cool_contract/contract.py
index 940b2f9..76d1be4 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/cool_contract/contract.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/cool_contract/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("cool_contract")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class CoolContract(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/cool_contract/deploy_config.py b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/cool_contract/deploy_config.py
index d33f65b..9ab7336 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/cool_contract/deploy_config.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/cool_contract/deploy_config.py
@@ -14,11 +14,11 @@ def deploy(
app_spec: algokit_utils.ApplicationSpecification,
deployer: algokit_utils.Account,
) -> None:
- from smart_contracts.artifacts.cool_contract.client import (
- CoolContractClient,
+ from smart_contracts.artifacts.hello_world.client import (
+ HelloWorldClient,
)
- app_client = CoolContractClient(
+ app_client = HelloWorldClient(
algod_client,
creator=deployer,
indexer_client=indexer_client,
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/hello_world/contract.py b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/helpers/build.py b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/helpers/build.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_python/tests/hello_world_test.py b/tests_generated/test_smart_contract_generator_default_starter_preset_python/tests/hello_world_test.py
index 50fd332..f4262b9 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_python/tests/hello_world_test.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_python/tests/hello_world_test.py
@@ -1,33 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2 b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
index 01e5881..83b938b 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/contract.py.j2
@@ -1,30 +1,8 @@
-import beaker
-import pyteal as pt
-{% if preset_name == 'starter' %}
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("{{ contract_name }}")
-{% elif preset_name == 'production' -%}
-from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME
-app = beaker.Application("{{ contract_name }}")
-
-
-@app.update(authorize=beaker.Authorize.only_creator(), bare=True)
-def update() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME),
- comment="Check app is updatable",
- )
-
-
-@app.delete(authorize=beaker.Authorize.only_creator(), bare=True)
-def delete() -> pt.Expr:
- return pt.Assert(
- pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME),
- comment="Check app is deletable",
- )
-{% endif %}
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class {{ contract_name.split('_')|map('capitalize')|join }}(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy-config.ts.j2 b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy-config.ts.j2
index 325fb24..c8b69ba 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy-config.ts.j2
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.algokit/generators/create_contract/smart_contracts/{{ contract_name }}/deploy-config.ts.j2
@@ -1,9 +1,9 @@
import * as algokit from '@algorandfoundation/algokit-utils'
-import { {{ contract_name.split('_')|map('capitalize')|join }}Client } from '../artifacts/{{ contract_name }}/client'
+import { HelloWorldClient } from '../artifacts/hello_world/client'
// Below is a showcase of various deployment options you can use in TypeScript Client
export async function deploy() {
- console.log('=== Deploying {{ contract_name.split('_')|map('capitalize')|join }} ===')
+ console.log('=== Deploying HelloWorld ===')
const algod = algokit.getAlgoClient()
const indexer = algokit.getAlgoIndexerClient()
@@ -16,7 +16,7 @@ export async function deploy() {
},
algod,
)
- const appClient = new {{ contract_name.split('_')|map('capitalize')|join }}Client(
+ const appClient = new HelloWorldClient(
{
resolveBy: 'creatorAndName',
findExistingUsing: indexer,
@@ -26,20 +26,11 @@ export async function deploy() {
algod,
)
- {%- if preset_name == 'starter' %}
const app = await appClient.deploy({
onSchemaBreak: 'append',
onUpdate: 'append',
})
- {% elif preset_name == 'production' %}
- const isMainNet = await algokit.isMainNet(algod)
- const app = await appClient.deploy({
- allowDelete: !isMainNet,
- allowUpdate: !isMainNet,
- onSchemaBreak: isMainNet ? 'append' : 'replace',
- onUpdate: isMainNet ? 'append' : 'update',
- })
- {% endif %}
+
// If app was just created fund the app account
if (['create', 'replace'].includes(app.operationPerformed)) {
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.copier-answers.yml b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.copier-answers.yml
index 11d110d..4e6d7e9 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.copier-answers.yml
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.copier-answers.yml
@@ -12,8 +12,13 @@ ide_vscode: true
indexer_port: 8980
indexer_server: http://localhost
indexer_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-preset_name: starter
project_name: test_smart_contract_generator_default_starter_preset_typescript
+python_linter: ruff
+use_dispenser: false
+use_github_actions: true
+use_pre_commit: true
use_python_black: true
+use_python_mypy: true
+use_python_pip_audit: true
use_python_pytest: true
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.github/workflows/cd.yaml b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.github/workflows/cd.yaml
new file mode 100644
index 0000000..3e0fd45
--- /dev/null
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.github/workflows/cd.yaml
@@ -0,0 +1,50 @@
+name: Continuous Delivery of Smart Contract
+
+on:
+ push:
+ branches:
+ - main
+
+concurrency: release
+
+jobs:
+ ci-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
+
+ deploy-testnet:
+ runs-on: 'ubuntu-latest'
+ needs: ci-check
+ environment: Test
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Deploy to testnet
+ run: algokit deploy testnet
+ env:
+ # This is the account that becomes the creator of the contract.
+ # Since we are not using the optional dispenser account (via DISPENSER_MNEMONIC),
+ # it must also be funded with enough Algos to deploy and fund the smart contracts created
+ DEPLOYER_MNEMONIC: ${{ secrets.DEPLOYER_MNEMONIC }}
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.github/workflows/checks.yaml b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.github/workflows/checks.yaml
new file mode 100644
index 0000000..eea57bf
--- /dev/null
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.github/workflows/checks.yaml
@@ -0,0 +1,79 @@
+name: Check code base
+
+on:
+ workflow_call:
+
+jobs:
+ checks:
+ runs-on: 'ubuntu-latest'
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v3
+
+ - name: Install poetry
+ run: pipx install poetry
+
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+ cache: 'poetry'
+
+ - name: Install algokit
+ run: pipx install algokit
+
+ - name: Start LocalNet
+ run: algokit localnet start
+
+ - name: Bootstrap dependencies
+ run: algokit bootstrap all
+
+ - name: Configure git
+ shell: bash
+ run: |
+ # set git user and email as test invoke git
+ git config --global user.email "actions@github.com" && git config --global user.name "github-actions"
+
+ - name: Audit with pip-audit
+ run: |
+ # audit non dev dependencies, no exclusions
+ poetry export --without=dev > requirements.txt && poetry run pip-audit -r requirements.txt
+
+ # audit all dependencies, with exclusions.
+ # If a vulnerability is found in a dev dependency without an available fix,
+ # it can be temporarily ignored by adding --ignore-vuln e.g.
+ # --ignore-vuln "GHSA-hcpj-qp55-gfph" # GitPython vulnerability, dev only dependency
+ poetry run pip-audit
+
+ - name: Check formatting with Black
+ run: |
+ # stop the build if there are files that don't meet formatting requirements
+ poetry run black --check .
+
+ - name: Check linting with Ruff
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ poetry run ruff .
+
+ - name: Check types with mypy
+ run: poetry run mypy
+
+ - name: Run tests
+ shell: bash
+ run: |
+ set -o pipefail
+ poetry run pytest --junitxml=pytest-junit.xml
+
+ - name: Build smart contracts
+ run: poetry run python -m smart_contracts build
+
+ - name: Check output stability of the smart contracts
+ shell: bash
+ run: |
+ # Add untracked files as empty so they come up in diff
+ git add -N ./smart_contracts/artifacts
+ # Error out if there are any changes in teal after generating output
+ git diff --exit-code --minimal ./smart_contracts/artifacts || (echo "::error ::Smart contract artifacts have changed, ensure committed artifacts are up to date" && exit 1);
+
+ - name: Run deployer against LocalNet
+ run: npm run --prefix smart_contracts deploy:ci
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.github/workflows/pr.yaml b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.github/workflows/pr.yaml
new file mode 100644
index 0000000..a80f784
--- /dev/null
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.github/workflows/pr.yaml
@@ -0,0 +1,8 @@
+name: Pull Request validation
+
+on: [pull_request]
+
+jobs:
+ pr-check:
+ name: Perform Checks
+ uses: ./.github/workflows/checks.yaml
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.pre-commit-config.yaml b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.pre-commit-config.yaml
new file mode 100644
index 0000000..93bfff5
--- /dev/null
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.pre-commit-config.yaml
@@ -0,0 +1,38 @@
+repos:
+ - repo: local
+ hooks:
+
+ - id: black
+ name: black
+ description: "Black: The uncompromising Python code formatter"
+ entry: poetry run black
+ language: system
+ minimum_pre_commit_version: 2.9.2
+ require_serial: true
+ types_or: [ python, pyi ]
+
+
+ - id: ruff
+ name: ruff
+ description: "Run 'ruff' for extremely fast Python linting"
+ entry: poetry run ruff
+ language: system
+ types: [ python ]
+ args: [ --fix ]
+ require_serial: false
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '0'
+ files: '^(src|tests)/'
+
+
+ - id: mypy
+ name: mypy
+ description: '`mypy` will check Python types for correctness'
+ entry: poetry run mypy
+ language: system
+ types_or: [ python, pyi ]
+ require_serial: true
+ additional_dependencies: [ ]
+ minimum_pre_commit_version: '2.9.2'
+ files: '^(src|tests)/'
+
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/extensions.json b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/extensions.json
index 5ed3b87..c170e6c 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/extensions.json
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/extensions.json
@@ -1,6 +1,8 @@
{
"recommendations": [
"ms-python.python",
+ "charliermarsh.ruff",
+ "matangover.mypy",
"ms-python.black-formatter",
"esbenp.prettier-vscode",
"tamasfe.even-better-toml",
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/launch.json b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/launch.json
index 4ccd8e1..b5c1fb6 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/launch.json
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
@@ -10,11 +10,11 @@
"cwd": "${workspaceFolder}/smart_contracts",
"console": "integratedTerminal",
"skipFiles": ["/**", "node_modules/**"],
- "preLaunchTask": "Build Beaker application (+ LocalNet)",
+ "preLaunchTask": "Build Puya application (+ LocalNet)",
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
@@ -25,7 +25,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/settings.json b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/settings.json
index 64ef130..50d7af1 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/settings.json
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/settings.json
@@ -28,6 +28,23 @@
},
"black-formatter.args": ["--config=pyproject.toml"],
"python.testing.pytestEnabled": true,
+ "ruff.enable": true,
+ "ruff.lint.run": "onSave",
+ "ruff.lint.args": ["--config=pyproject.toml"],
+ "ruff.importStrategy": "fromEnvironment",
+ "ruff.fixAll": true, //lint and fix all files in workspace
+ "ruff.organizeImports": true, //organize imports on save
+ "ruff.codeAction.disableRuleComment": {
+ "enable": true
+ },
+ "ruff.codeAction.fixViolation": {
+ "enable": true
+ },
+ "python.analysis.typeCheckingMode": "off",
+ "mypy.configFile": "pyproject.toml",
+ // set to empty array to use config from project
+ "mypy.targets": [],
+ "mypy.runUsingActiveInterpreter": true,
// On Windows, if execution policy is set to Signed (default) then it won't be able to activate the venv
// so instead let's set it to RemoteSigned for VS Code terminal
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/tasks.json b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/tasks.json
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/README.md b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/README.md
index d9dc4f2..c94195b 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/README.md
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -40,7 +47,46 @@ This project has been generated using AlgoKit. See below for default getting sta
1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again
2. Follow step 3 above
-> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.
+> For guidance on `smart_contracts` folder and adding new contracts to the project please see [README](smart_contracts/README.md) on the respective folder.### Continuous Integration / Continuous Deployment (CI/CD)
+
+This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI/CD workflows, which are located in the [`.github/workflows`](./.github/workflows) folder.
+
+#### Setting up GitHub for CI/CD workflow and TestNet deployment
+
+ 1. Every time you have a change to your smart contract, and when you first initialize the project you need to [build the contract](#initial-setup) and then commit the `smart_contracts/artifacts` folder so the [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) tests pass
+ 2. Decide what values you want to use for the `allowUpdate` and `allowDelete` parameters specified in [`deploy-config.ts`](./smart_contracts/hello_world/deploy-config.ts).
+ When deploying to LocalNet these values are both set to `true` for convenience. But for non-LocalNet networks
+ they are more conservative and use `false`
+ These default values will allow the smart contract to be deployed initially, but will not allow the app to be updated or deleted if is changed and the build will instead fail.
+ To help you decide it may be helpful to read the [AlgoKit Utils app deployment documentation](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/docs/capabilities/app-deploy.md) or the [AlgoKit smart contract deployment architecture](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md#upgradeable-and-deletable-contracts).
+ 3. Create a [Github Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#creating-an-environment) named `Test`.
+ Note: If you have a private repository and don't have GitHub Enterprise then Environments won't work and you'll need to convert the GitHub Action to use a different approach. Ignore this step if you picked `Starter` preset.
+ 4. Create or obtain a mnemonic for an Algorand account for use on TestNet to deploy apps, referred to as the `DEPLOYER` account.
+ 5. Store the mnemonic as a [secret](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-secrets) `DEPLOYER_MNEMONIC`
+ in the Test environment created in step 3.
+ 6. The account used to deploy the smart contract will require enough funds to create the app, and also fund it. There are two approaches available here:
+ * Either, ensure the account is funded outside of CI/CD.
+ In Testnet, funds can be obtained by using the [Algorand TestNet dispenser](https://bank.testnet.algorand.network/) and we recommend provisioning 50 ALGOs.
+ * Or, fund the account as part of the CI/CD process by using a `DISPENSER_MNEMONIC` GitHub Environment secret to point to a separate `DISPENSER` account that you maintain ALGOs in (similarly, you need to provision ALGOs into this account using the [TestNet dispenser](https://bank.testnet.algorand.network/)).
+
+#### Continuous Integration
+
+For pull requests and pushes to `main` branch against this repository the following checks are automatically performed by GitHub Actions:
+ - Python dependencies are audited using [pip-audit](https://pypi.org/project/pip-audit/)
+ - Code formatting is checked using [Black](https://github.com/psf/black)
+ - Linting is checked using [Ruff](https://github.com/charliermarsh/ruff)
+ - Types are checked using [mypy](https://mypy-lang.org/)
+ - Python tests are executed using [pytest](https://docs.pytest.org/)
+ - Smart contract artifacts are built
+ - Smart contract artifacts are checked for [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md)
+ - Smart contract is deployed to a AlgoKit LocalNet instance
+
+#### Continuous Deployment
+
+For pushes to `main` branch, after the above checks pass, the following deployment actions are performed:
+ - The smart contract(s) are deployed to TestNet using [AlgoNode](https://algonode.io).
+
+> Please note deployment is also performed via `algokit deploy` command which can be invoked both via CI as seen on this project, or locally. For more information on how to use `algokit deploy` please see [AlgoKit documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/deploy.md).
# Tools
@@ -48,12 +94,15 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-ts) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
-- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
+- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.- [Ruff](https://github.com/charliermarsh/ruff): An extremely fast Python linter.
+
+- [mypy](https://mypy-lang.org/): Static type checker.
- [pytest](https://docs.pytest.org/): Automated testing.
- [pip-audit](https://pypi.org/project/pip-audit/): Tool for scanning Python environments for packages with known vulnerabilities.
+ - [pre-commit](https://pre-commit.com/): A framework for managing and maintaining multi-language pre-commit hooks, to enable pre-commit you need to run `pre-commit install` in the root of the repository. This will install the pre-commit hooks and run them against modified files when committing. If any of the hooks fail, the commit will be aborted. To run the hooks on all files, use `pre-commit run --all-files`.
- [npm](https://www.npmjs.com/): Node.js package manager
- [TypeScript](https://www.typescriptlang.org/): Strongly typed programming language that builds on JavaScript
- [ts-node-dev](https://github.com/wclr/ts-node-dev): TypeScript development execution environment
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/pyproject.toml b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/pyproject.toml
index b4a48ee..b825fb8 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/pyproject.toml
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/pyproject.toml
@@ -6,21 +6,45 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
+ruff = "^0.1.6"
+mypy = "*"
pytest = "*"
pytest-cov = "*"
pip-audit = "*"
+pre-commit = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
+[tool.ruff]
+line-length = 120
+select = ["E", "F", "ANN", "UP", "N", "C4", "B", "A", "YTT", "W", "FBT", "Q", "RUF", "I"]
+ignore = [
+ "ANN101", # no type for self
+ "ANN102", # no type for cls
+]
+unfixable = ["B", "RUF"]
+
+[tool.ruff.flake8-annotations]
+allow-star-arg-any = true
+suppress-none-returning = true
[tool.pytest.ini_options]
pythonpath = ["smart_contracts", "tests"]
+
+[tool.mypy]
+files = "smart_contracts/"
+python_version = "3.12"
+check_untyped_defs = true
+warn_redundant_casts = true
+warn_unused_ignores = true
+allow_untyped_defs = false
+strict_equality = true
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/__main__.py b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/__main__.py
index 0026e40..b91ab2e 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/__main__.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/__main__.py
@@ -21,8 +21,8 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
if __name__ == "__main__":
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/config.py b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/config.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/cool_contract/contract.py b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/cool_contract/contract.py
index 940b2f9..76d1be4 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/cool_contract/contract.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/cool_contract/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("cool_contract")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class CoolContract(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/cool_contract/deploy-config.ts b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/cool_contract/deploy-config.ts
index 4e8229f..c8b69ba 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/cool_contract/deploy-config.ts
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/cool_contract/deploy-config.ts
@@ -1,9 +1,9 @@
import * as algokit from '@algorandfoundation/algokit-utils'
-import { CoolContractClient } from '../artifacts/cool_contract/client'
+import { HelloWorldClient } from '../artifacts/hello_world/client'
// Below is a showcase of various deployment options you can use in TypeScript Client
export async function deploy() {
- console.log('=== Deploying CoolContract ===')
+ console.log('=== Deploying HelloWorld ===')
const algod = algokit.getAlgoClient()
const indexer = algokit.getAlgoIndexerClient()
@@ -16,7 +16,7 @@ export async function deploy() {
},
algod,
)
- const appClient = new CoolContractClient(
+ const appClient = new HelloWorldClient(
{
resolveBy: 'creatorAndName',
findExistingUsing: indexer,
@@ -25,11 +25,12 @@ export async function deploy() {
},
algod,
)
+
const app = await appClient.deploy({
onSchemaBreak: 'append',
onUpdate: 'append',
})
-
+
// If app was just created fund the app account
if (['create', 'replace'].includes(app.operationPerformed)) {
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/hello_world/contract.py b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/hello_world/deploy-config.ts b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/hello_world/deploy-config.ts
index 527fe2c..c8b69ba 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/hello_world/deploy-config.ts
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/hello_world/deploy-config.ts
@@ -25,11 +25,12 @@ export async function deploy() {
},
algod,
)
+
const app = await appClient.deploy({
onSchemaBreak: 'append',
onUpdate: 'append',
})
-
+
// If app was just created fund the app account
if (['create', 'replace'].includes(app.operationPerformed)) {
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/helpers/build.py b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/helpers/build.py
index 20d6d6d..67377d3 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/helpers/build.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "ts"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/tests/hello_world_test.py b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/tests/hello_world_test.py
index 50fd332..f4262b9 100644
--- a/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/tests/hello_world_test.py
+++ b/tests_generated/test_smart_contract_generator_default_starter_preset_typescript/tests/hello_world_test.py
@@ -1,33 +1,32 @@
+import algokit_utils
import pytest
-from algokit_utils import (
- ApplicationClient,
- ApplicationSpecification,
- get_localnet_default_account,
-)
+from algokit_utils import get_localnet_default_account
from algosdk.v2client.algod import AlgodClient
+from algosdk.v2client.indexer import IndexerClient
-from smart_contracts.hello_world import contract as hello_world_contract
-
-
-@pytest.fixture(scope="session")
-def hello_world_app_spec(algod_client: AlgodClient) -> ApplicationSpecification:
- return hello_world_contract.app.build(algod_client)
+from smart_contracts.artifacts.hello_world.client import HelloWorldClient
@pytest.fixture(scope="session")
def hello_world_client(
- algod_client: AlgodClient, hello_world_app_spec: ApplicationSpecification
-) -> ApplicationClient:
- client = ApplicationClient(
+ algod_client: AlgodClient, indexer_client: IndexerClient
+) -> HelloWorldClient:
+ client = HelloWorldClient(
algod_client,
- app_spec=hello_world_app_spec,
- signer=get_localnet_default_account(algod_client),
+ creator=get_localnet_default_account(algod_client),
+ indexer_client=indexer_client,
+ )
+
+ client.deploy(
+ on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
+ on_update=algokit_utils.OnUpdate.UpdateApp,
+ allow_delete=True,
+ allow_update=True,
)
- client.create()
return client
-def test_says_hello(hello_world_client: ApplicationClient) -> None:
- result = hello_world_client.call(hello_world_contract.hello, name="World")
+def test_says_hello(hello_world_client: HelloWorldClient) -> None:
+ result = hello_world_client.hello(name="World")
assert result.return_value == "Hello, World"
diff --git a/tests_generated/test_use_github_actions-False/.vscode/launch.json b/tests_generated/test_use_github_actions-False/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_use_github_actions-False/.vscode/launch.json
+++ b/tests_generated/test_use_github_actions-False/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_use_github_actions-False/.vscode/tasks.json b/tests_generated/test_use_github_actions-False/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_use_github_actions-False/.vscode/tasks.json
+++ b/tests_generated/test_use_github_actions-False/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_use_github_actions-False/README.md b/tests_generated/test_use_github_actions-False/README.md
index 28d7d9c..b32a2c2 100644
--- a/tests_generated/test_use_github_actions-False/README.md
+++ b/tests_generated/test_use_github_actions-False/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -47,7 +54,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
diff --git a/tests_generated/test_use_github_actions-False/pyproject.toml b/tests_generated/test_use_github_actions-False/pyproject.toml
index 58f6fee..7e0df16 100644
--- a/tests_generated/test_use_github_actions-False/pyproject.toml
+++ b/tests_generated/test_use_github_actions-False/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
diff --git a/tests_generated/test_use_github_actions-False/smart_contracts/__main__.py b/tests_generated/test_use_github_actions-False/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_use_github_actions-False/smart_contracts/__main__.py
+++ b/tests_generated/test_use_github_actions-False/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_use_github_actions-False/smart_contracts/config.py b/tests_generated/test_use_github_actions-False/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_use_github_actions-False/smart_contracts/config.py
+++ b/tests_generated/test_use_github_actions-False/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_use_github_actions-False/smart_contracts/hello_world/contract.py b/tests_generated/test_use_github_actions-False/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_use_github_actions-False/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_use_github_actions-False/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_use_github_actions-False/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_use_github_actions-False/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_use_github_actions-False/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_use_github_actions-False/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_use_github_actions-False/smart_contracts/helpers/build.py b/tests_generated/test_use_github_actions-False/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_use_github_actions-False/smart_contracts/helpers/build.py
+++ b/tests_generated/test_use_github_actions-False/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_use_github_actions-True/.vscode/launch.json b/tests_generated/test_use_github_actions-True/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_use_github_actions-True/.vscode/launch.json
+++ b/tests_generated/test_use_github_actions-True/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_use_github_actions-True/.vscode/tasks.json b/tests_generated/test_use_github_actions-True/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_use_github_actions-True/.vscode/tasks.json
+++ b/tests_generated/test_use_github_actions-True/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_use_github_actions-True/README.md b/tests_generated/test_use_github_actions-True/README.md
index 3732e0f..140c74c 100644
--- a/tests_generated/test_use_github_actions-True/README.md
+++ b/tests_generated/test_use_github_actions-True/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -84,7 +91,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
diff --git a/tests_generated/test_use_github_actions-True/pyproject.toml b/tests_generated/test_use_github_actions-True/pyproject.toml
index fb3ee58..0176f57 100644
--- a/tests_generated/test_use_github_actions-True/pyproject.toml
+++ b/tests_generated/test_use_github_actions-True/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
diff --git a/tests_generated/test_use_github_actions-True/smart_contracts/__main__.py b/tests_generated/test_use_github_actions-True/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_use_github_actions-True/smart_contracts/__main__.py
+++ b/tests_generated/test_use_github_actions-True/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_use_github_actions-True/smart_contracts/config.py b/tests_generated/test_use_github_actions-True/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_use_github_actions-True/smart_contracts/config.py
+++ b/tests_generated/test_use_github_actions-True/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_use_github_actions-True/smart_contracts/hello_world/contract.py b/tests_generated/test_use_github_actions-True/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_use_github_actions-True/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_use_github_actions-True/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_use_github_actions-True/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_use_github_actions-True/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_use_github_actions-True/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_use_github_actions-True/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_use_github_actions-True/smart_contracts/helpers/build.py b/tests_generated/test_use_github_actions-True/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_use_github_actions-True/smart_contracts/helpers/build.py
+++ b/tests_generated/test_use_github_actions-True/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_use_python_black-False/.vscode/launch.json b/tests_generated/test_use_python_black-False/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_use_python_black-False/.vscode/launch.json
+++ b/tests_generated/test_use_python_black-False/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_use_python_black-False/.vscode/tasks.json b/tests_generated/test_use_python_black-False/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_use_python_black-False/.vscode/tasks.json
+++ b/tests_generated/test_use_python_black-False/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_use_python_black-False/README.md b/tests_generated/test_use_python_black-False/README.md
index 8633efa..90d11f6 100644
--- a/tests_generated/test_use_python_black-False/README.md
+++ b/tests_generated/test_use_python_black-False/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -47,7 +54,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.
diff --git a/tests_generated/test_use_python_black-False/pyproject.toml b/tests_generated/test_use_python_black-False/pyproject.toml
index 07a3d16..e40a80d 100644
--- a/tests_generated/test_use_python_black-False/pyproject.toml
+++ b/tests_generated/test_use_python_black-False/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
pytest = "*"
diff --git a/tests_generated/test_use_python_black-False/smart_contracts/__main__.py b/tests_generated/test_use_python_black-False/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_use_python_black-False/smart_contracts/__main__.py
+++ b/tests_generated/test_use_python_black-False/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_use_python_black-False/smart_contracts/config.py b/tests_generated/test_use_python_black-False/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_use_python_black-False/smart_contracts/config.py
+++ b/tests_generated/test_use_python_black-False/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_use_python_black-False/smart_contracts/hello_world/contract.py b/tests_generated/test_use_python_black-False/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_use_python_black-False/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_use_python_black-False/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_use_python_black-False/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_use_python_black-False/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_use_python_black-False/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_use_python_black-False/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_use_python_black-False/smart_contracts/helpers/build.py b/tests_generated/test_use_python_black-False/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_use_python_black-False/smart_contracts/helpers/build.py
+++ b/tests_generated/test_use_python_black-False/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_use_python_black-True/.vscode/launch.json b/tests_generated/test_use_python_black-True/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_use_python_black-True/.vscode/launch.json
+++ b/tests_generated/test_use_python_black-True/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_use_python_black-True/.vscode/tasks.json b/tests_generated/test_use_python_black-True/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_use_python_black-True/.vscode/tasks.json
+++ b/tests_generated/test_use_python_black-True/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_use_python_black-True/README.md b/tests_generated/test_use_python_black-True/README.md
index 4455fec..24653d6 100644
--- a/tests_generated/test_use_python_black-True/README.md
+++ b/tests_generated/test_use_python_black-True/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -47,7 +54,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
diff --git a/tests_generated/test_use_python_black-True/pyproject.toml b/tests_generated/test_use_python_black-True/pyproject.toml
index 2e666f9..d564b1a 100644
--- a/tests_generated/test_use_python_black-True/pyproject.toml
+++ b/tests_generated/test_use_python_black-True/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
diff --git a/tests_generated/test_use_python_black-True/smart_contracts/__main__.py b/tests_generated/test_use_python_black-True/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_use_python_black-True/smart_contracts/__main__.py
+++ b/tests_generated/test_use_python_black-True/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_use_python_black-True/smart_contracts/config.py b/tests_generated/test_use_python_black-True/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_use_python_black-True/smart_contracts/config.py
+++ b/tests_generated/test_use_python_black-True/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_use_python_black-True/smart_contracts/hello_world/contract.py b/tests_generated/test_use_python_black-True/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_use_python_black-True/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_use_python_black-True/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_use_python_black-True/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_use_python_black-True/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_use_python_black-True/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_use_python_black-True/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_use_python_black-True/smart_contracts/helpers/build.py b/tests_generated/test_use_python_black-True/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_use_python_black-True/smart_contracts/helpers/build.py
+++ b/tests_generated/test_use_python_black-True/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_use_python_mypy-False/.vscode/launch.json b/tests_generated/test_use_python_mypy-False/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_use_python_mypy-False/.vscode/launch.json
+++ b/tests_generated/test_use_python_mypy-False/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_use_python_mypy-False/.vscode/tasks.json b/tests_generated/test_use_python_mypy-False/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_use_python_mypy-False/.vscode/tasks.json
+++ b/tests_generated/test_use_python_mypy-False/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_use_python_mypy-False/README.md b/tests_generated/test_use_python_mypy-False/README.md
index ad83b07..3cd407a 100644
--- a/tests_generated/test_use_python_mypy-False/README.md
+++ b/tests_generated/test_use_python_mypy-False/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -47,7 +54,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
diff --git a/tests_generated/test_use_python_mypy-False/pyproject.toml b/tests_generated/test_use_python_mypy-False/pyproject.toml
index 0f019b6..f59ce5e 100644
--- a/tests_generated/test_use_python_mypy-False/pyproject.toml
+++ b/tests_generated/test_use_python_mypy-False/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
diff --git a/tests_generated/test_use_python_mypy-False/smart_contracts/__main__.py b/tests_generated/test_use_python_mypy-False/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_use_python_mypy-False/smart_contracts/__main__.py
+++ b/tests_generated/test_use_python_mypy-False/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_use_python_mypy-False/smart_contracts/config.py b/tests_generated/test_use_python_mypy-False/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_use_python_mypy-False/smart_contracts/config.py
+++ b/tests_generated/test_use_python_mypy-False/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_use_python_mypy-False/smart_contracts/hello_world/contract.py b/tests_generated/test_use_python_mypy-False/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_use_python_mypy-False/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_use_python_mypy-False/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_use_python_mypy-False/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_use_python_mypy-False/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_use_python_mypy-False/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_use_python_mypy-False/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_use_python_mypy-False/smart_contracts/helpers/build.py b/tests_generated/test_use_python_mypy-False/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_use_python_mypy-False/smart_contracts/helpers/build.py
+++ b/tests_generated/test_use_python_mypy-False/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_use_python_mypy-True/.vscode/launch.json b/tests_generated/test_use_python_mypy-True/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_use_python_mypy-True/.vscode/launch.json
+++ b/tests_generated/test_use_python_mypy-True/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_use_python_mypy-True/.vscode/tasks.json b/tests_generated/test_use_python_mypy-True/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_use_python_mypy-True/.vscode/tasks.json
+++ b/tests_generated/test_use_python_mypy-True/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_use_python_mypy-True/README.md b/tests_generated/test_use_python_mypy-True/README.md
index 1555e7d..f77cb6f 100644
--- a/tests_generated/test_use_python_mypy-True/README.md
+++ b/tests_generated/test_use_python_mypy-True/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -47,7 +54,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
diff --git a/tests_generated/test_use_python_mypy-True/pyproject.toml b/tests_generated/test_use_python_mypy-True/pyproject.toml
index 3a197cf..8501e51 100644
--- a/tests_generated/test_use_python_mypy-True/pyproject.toml
+++ b/tests_generated/test_use_python_mypy-True/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
diff --git a/tests_generated/test_use_python_mypy-True/smart_contracts/__main__.py b/tests_generated/test_use_python_mypy-True/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_use_python_mypy-True/smart_contracts/__main__.py
+++ b/tests_generated/test_use_python_mypy-True/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_use_python_mypy-True/smart_contracts/config.py b/tests_generated/test_use_python_mypy-True/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_use_python_mypy-True/smart_contracts/config.py
+++ b/tests_generated/test_use_python_mypy-True/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_use_python_mypy-True/smart_contracts/hello_world/contract.py b/tests_generated/test_use_python_mypy-True/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_use_python_mypy-True/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_use_python_mypy-True/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_use_python_mypy-True/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_use_python_mypy-True/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_use_python_mypy-True/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_use_python_mypy-True/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_use_python_mypy-True/smart_contracts/helpers/build.py b/tests_generated/test_use_python_mypy-True/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_use_python_mypy-True/smart_contracts/helpers/build.py
+++ b/tests_generated/test_use_python_mypy-True/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_use_python_pytest-False/.vscode/launch.json b/tests_generated/test_use_python_pytest-False/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_use_python_pytest-False/.vscode/launch.json
+++ b/tests_generated/test_use_python_pytest-False/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_use_python_pytest-False/.vscode/tasks.json b/tests_generated/test_use_python_pytest-False/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_use_python_pytest-False/.vscode/tasks.json
+++ b/tests_generated/test_use_python_pytest-False/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_use_python_pytest-False/README.md b/tests_generated/test_use_python_pytest-False/README.md
index 9e17288..7869736 100644
--- a/tests_generated/test_use_python_pytest-False/README.md
+++ b/tests_generated/test_use_python_pytest-False/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -47,7 +54,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
diff --git a/tests_generated/test_use_python_pytest-False/pyproject.toml b/tests_generated/test_use_python_pytest-False/pyproject.toml
index 6984e54..d4756b8 100644
--- a/tests_generated/test_use_python_pytest-False/pyproject.toml
+++ b/tests_generated/test_use_python_pytest-False/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
diff --git a/tests_generated/test_use_python_pytest-False/smart_contracts/__main__.py b/tests_generated/test_use_python_pytest-False/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_use_python_pytest-False/smart_contracts/__main__.py
+++ b/tests_generated/test_use_python_pytest-False/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_use_python_pytest-False/smart_contracts/config.py b/tests_generated/test_use_python_pytest-False/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_use_python_pytest-False/smart_contracts/config.py
+++ b/tests_generated/test_use_python_pytest-False/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_use_python_pytest-False/smart_contracts/hello_world/contract.py b/tests_generated/test_use_python_pytest-False/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_use_python_pytest-False/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_use_python_pytest-False/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_use_python_pytest-False/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_use_python_pytest-False/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_use_python_pytest-False/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_use_python_pytest-False/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_use_python_pytest-False/smart_contracts/helpers/build.py b/tests_generated/test_use_python_pytest-False/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_use_python_pytest-False/smart_contracts/helpers/build.py
+++ b/tests_generated/test_use_python_pytest-False/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"
diff --git a/tests_generated/test_use_python_pytest-True/.vscode/launch.json b/tests_generated/test_use_python_pytest-True/.vscode/launch.json
index 8a39d26..d127326 100644
--- a/tests_generated/test_use_python_pytest-True/.vscode/launch.json
+++ b/tests_generated/test_use_python_pytest-True/.vscode/launch.json
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Build & Deploy Beaker application",
+ "name": "Build & Deploy Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -11,7 +11,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Deploy Built Beaker application",
+ "name": "Deploy Built Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
@@ -20,7 +20,7 @@
"envFile": "${workspaceFolder}/.env.localnet"
},
{
- "name": "Build Beaker application",
+ "name": "Build Puya application",
"type": "python",
"request": "launch",
"module": "smart_contracts",
diff --git a/tests_generated/test_use_python_pytest-True/.vscode/tasks.json b/tests_generated/test_use_python_pytest-True/.vscode/tasks.json
index fe7889a..4873ec8 100644
--- a/tests_generated/test_use_python_pytest-True/.vscode/tasks.json
+++ b/tests_generated/test_use_python_pytest-True/.vscode/tasks.json
@@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Build Beaker application",
+ "label": "Build Puya application",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
@@ -18,7 +18,7 @@
"problemMatcher": []
},
{
- "label": "Build Beaker application (+ LocalNet)",
+ "label": "Build Puya application (+ LocalNet)",
"command": "${workspaceFolder}/.venv/bin/python",
"windows": {
"command": "${workspaceFolder}/.venv/Scripts/python.exe"
diff --git a/tests_generated/test_use_python_pytest-True/README.md b/tests_generated/test_use_python_pytest-True/README.md
index b9ba1a7..1731c5b 100644
--- a/tests_generated/test_use_python_pytest-True/README.md
+++ b/tests_generated/test_use_python_pytest-True/README.md
@@ -4,14 +4,21 @@ This project has been generated using AlgoKit. See below for default getting sta
# Setup
+### Pre-requisites
+
+- [Python 3.12](https://www.python.org/downloads/) or later
+- [Docker](https://www.docker.com/) (only required for LocalNet)
+
+> Please note `Puya` smart contract development language is currently in alpha / developer preview. It is not recommended for production usage yet.
+
### Initial setup
1. Clone this repository locally
2. Install pre-requisites:
- Make sure to have [Docker](https://www.docker.com/) installed and running on your machine.
- - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later.
+ - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The recommended version is `1.7.3`. Ensure you can execute `algokit --version` and get `1.7.1` or later.
- Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will:
- - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `1.2`. Ensure you can execute `poetry -V` and get `1.2`+
+ - Install `Poetry` - [Link](https://python-poetry.org/docs/#installation): The minimum required version is `^1.7`. Ensure you can execute `poetry -V` and get `1.2`+
- Run `poetry install` in the root directory, which will set up a `.venv` folder with a Python virtual environment and also install all Python dependencies
- Copy `.env.template` to `.env`
- Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you.
@@ -47,7 +54,7 @@ This project makes use of Python to build Algorand smart contracts. The followin
- [Algorand](https://www.algorand.com/) - Layer 1 Blockchain; [Developer portal](https://developer.algorand.org/), [Why Algorand?](https://developer.algorand.org/docs/get-started/basics/why_algorand/)
- [AlgoKit](https://github.com/algorandfoundation/algokit-cli) - One-stop shop tool for developers building on the Algorand network; [docs](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md), [intro tutorial](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/tutorials/intro.md)
-- [Beaker](https://github.com/algorand-devrel/beaker) - Smart contract development framework for PyTeal; [docs](https://beaker.algo.xyz), [examples](https://github.com/algorand-devrel/beaker/tree/master/examples)
+- [Puya](https://github.com/algorand-foundation/puya) - Smart contract development framework for developing Algorand smart contracts in pure Python; [docs](https://github.com/algorandfoundation/puya), [examples](https://github.com/algorandfoundation/puya/tree/main/examples)
- [PyTEAL](https://github.com/algorand/pyteal) - Python language binding for Algorand smart contracts; [docs](https://pyteal.readthedocs.io/en/stable/)
- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-py) - A set of core Algorand utilities that make it easier to build solutions on Algorand.
- [Poetry](https://python-poetry.org/): Python packaging and dependency management.- [Black](https://github.com/psf/black): A Python code formatter.
diff --git a/tests_generated/test_use_python_pytest-True/pyproject.toml b/tests_generated/test_use_python_pytest-True/pyproject.toml
index fbca8d6..b8ea853 100644
--- a/tests_generated/test_use_python_pytest-True/pyproject.toml
+++ b/tests_generated/test_use_python_pytest-True/pyproject.toml
@@ -6,10 +6,10 @@ authors = ["None "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.10"
-beaker-pyteal = "^1.1.1"
+python = "^3.12"
algokit-utils = "^2.0.1"
python-dotenv = "^1.0.0"
+puya = "^0.1.3"
[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "*"}
diff --git a/tests_generated/test_use_python_pytest-True/smart_contracts/__main__.py b/tests_generated/test_use_python_pytest-True/smart_contracts/__main__.py
index 3ef8a27..75df051 100644
--- a/tests_generated/test_use_python_pytest-True/smart_contracts/__main__.py
+++ b/tests_generated/test_use_python_pytest-True/smart_contracts/__main__.py
@@ -22,19 +22,19 @@ def main(action: str) -> None:
match action:
case "build":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- build(artifact_path / contract.app.name, contract.app)
+ logger.info(f"Building app at {contract.path}")
+ build(artifact_path / contract.name, contract.path)
case "deploy":
for contract in contracts:
- logger.info(f"Deploying app {contract.app.name}")
- app_spec_path = artifact_path / contract.app.name / "application.json"
+ logger.info(f"Deploying app {contract.name}")
+ app_spec_path = artifact_path / contract.name / "application.json"
if contract.deploy:
deploy(app_spec_path, contract.deploy)
case "all":
for contract in contracts:
- logger.info(f"Building app {contract.app.name}")
- app_spec_path = build(artifact_path / contract.app.name, contract.app)
- logger.info(f"Deploying {contract.app.name}")
+ logger.info(f"Building app at {contract.path}")
+ app_spec_path = build(artifact_path / contract.name, contract.path)
+ logger.info(f"Deploying {contract.path.name}")
if contract.deploy:
deploy(app_spec_path, contract.deploy)
diff --git a/tests_generated/test_use_python_pytest-True/smart_contracts/config.py b/tests_generated/test_use_python_pytest-True/smart_contracts/config.py
index 8cefdd6..9c9076a 100644
--- a/tests_generated/test_use_python_pytest-True/smart_contracts/config.py
+++ b/tests_generated/test_use_python_pytest-True/smart_contracts/config.py
@@ -6,26 +6,24 @@
from algokit_utils import Account, ApplicationSpecification
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
-from beaker import Application
@dataclasses.dataclass
class SmartContract:
- app: Application
+ path: Path
+ name: str
deploy: Callable[
[AlgodClient, IndexerClient, ApplicationSpecification, Account], None
] | None = None
-def import_contract(folder: Path) -> Application:
+def import_contract(folder: Path) -> Path:
"""Imports the contract from a folder if it exists."""
- try:
- contract_module = importlib.import_module(
- f"{folder.parent.name}.{folder.name}.contract"
- )
- return contract_module.app
- except ImportError as e:
- raise Exception(f"Contract not found in {folder}") from e
+ contract_path = folder / "contract.py"
+ if contract_path.exists():
+ return contract_path
+ else:
+ raise Exception(f"Contract not found in {folder}")
def import_deploy_if_exists(
@@ -52,13 +50,11 @@ def has_contract_file(directory: Path) -> bool:
# define contracts to build and/or deploy
base_dir = Path("smart_contracts")
contracts = [
- SmartContract(app=import_contract(folder), deploy=import_deploy_if_exists(folder))
+ SmartContract(
+ path=import_contract(folder),
+ name=folder.name,
+ deploy=import_deploy_if_exists(folder),
+ )
for folder in base_dir.iterdir()
if folder.is_dir() and has_contract_file(folder)
]
-
-## Comment the above and uncomment the below and define contracts manually if you want to build and specify them
-## manually otherwise the above code will always include all contracts under contract.py file for any subdirectory
-## in the smart_contracts directory. Optionally it will also grab the deploy function from deploy_config.py if it exists.
-
-# contracts = []
diff --git a/tests_generated/test_use_python_pytest-True/smart_contracts/hello_world/contract.py b/tests_generated/test_use_python_pytest-True/smart_contracts/hello_world/contract.py
index 5ed8de0..1b8fddb 100644
--- a/tests_generated/test_use_python_pytest-True/smart_contracts/hello_world/contract.py
+++ b/tests_generated/test_use_python_pytest-True/smart_contracts/hello_world/contract.py
@@ -1,10 +1,8 @@
-import beaker
-import pyteal as pt
+from puyapy import ARC4Contract, Bytes
+from puyapy.arc4 import String, abimethod
-app = beaker.Application("hello_world")
-
-
-@app.external
-def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr:
- return output.set(pt.Concat(pt.Bytes("Hello, "), name.get()))
+class HelloWorld(ARC4Contract):
+ @abimethod()
+ def hello(self, name: String) -> String:
+ return String.encode(Bytes(b"Hello ") + name.decode())
diff --git a/tests_generated/test_use_python_pytest-True/smart_contracts/hello_world/deploy_config.py b/tests_generated/test_use_python_pytest-True/smart_contracts/hello_world/deploy_config.py
index 4afdc60..9ab7336 100644
--- a/tests_generated/test_use_python_pytest-True/smart_contracts/hello_world/deploy_config.py
+++ b/tests_generated/test_use_python_pytest-True/smart_contracts/hello_world/deploy_config.py
@@ -27,7 +27,6 @@ def deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
-
name = "world"
response = app_client.hello(name=name)
logger.info(
diff --git a/tests_generated/test_use_python_pytest-True/smart_contracts/helpers/build.py b/tests_generated/test_use_python_pytest-True/smart_contracts/helpers/build.py
index 201e5d6..0dad0c8 100644
--- a/tests_generated/test_use_python_pytest-True/smart_contracts/helpers/build.py
+++ b/tests_generated/test_use_python_pytest-True/smart_contracts/helpers/build.py
@@ -3,22 +3,34 @@
from pathlib import Path
from shutil import rmtree
-import beaker
-
logger = logging.getLogger(__name__)
deployment_extension = "py"
-def build(output_dir: Path, app: beaker.Application) -> Path:
+def build(output_dir: Path, contract_path: Path) -> Path:
output_dir = output_dir.resolve()
if output_dir.exists():
rmtree(output_dir)
output_dir.mkdir(exist_ok=True, parents=True)
- logger.info(f"Exporting {app.name} to {output_dir}")
- specification = app.build()
- specification.export(output_dir)
+ logger.info(f"Exporting {contract_path} to {output_dir}")
- result = subprocess.run(
+ build_result = subprocess.run(
+ [
+ "poetry",
+ "run",
+ "puyapy",
+ contract_path.absolute(),
+ f"--out-dir={output_dir}",
+ "--output-arc32",
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ if build_result.returncode:
+ raise Exception(f"Could not build contract:\n{build_result.stdout}")
+
+ generate_result = subprocess.run(
[
"algokit",
"generate",
@@ -31,13 +43,14 @@ def build(output_dir: Path, app: beaker.Application) -> Path:
stderr=subprocess.STDOUT,
text=True,
)
- if result.returncode:
- if "No such command" in result.stdout:
+ if generate_result.returncode:
+ if "No such command" in generate_result.stdout:
raise Exception(
"Could not generate typed client, requires AlgoKit 1.1 or "
"later. Please update AlgoKit"
)
else:
- raise Exception(f"Could not generate typed client:\n{result.stdout}")
-
+ raise Exception(
+ f"Could not generate typed client:\n{generate_result.stdout}"
+ )
return output_dir / "application.json"