Repository: vinteumorg/Floresta
Pull request #402: Re-structured functional tests.
Author: login: qlrd
Labels: name: dependencies
description: Pull requests that update a dependency file
name: code quality
description: Generally improves code readability and maintainability
name: functional tests
Created: 2025-03-07T14:34:25Z | Merged: 2025-03-12T16:19:02Z

Improves https://github.com/vinteumorg/Floresta/issues/252

### What is the purpose of this pull request?

- [ ] Bug fix
- [ ] Documentation update
- [ ] New feature
- [x] Test
- [ ] Other: <!-- Please describe it -->

### Which crates are being modified?

- [ ] floresta-chain
- [ ] floresta-cli
- [ ] floresta-common
- [ ] floresta-compact-filters
- [ ] floresta-electrum
- [ ] floresta-watch-only
- [ ] floresta-wire
- [ ] floresta
- [ ] florestad
- [ ] Other: <!-- Please describe it -->.

### Description

This re-structure aims to optmize developer flow and the experience with tests tool through:

* a replacement of the current python package management;
* a more organized folder tree strucutre inside tests/; and
* changes in tests/run_tests.py, tests/prepare.sh and tests/run.sh to
comply with the already mentioned changes.

The replacement in python package management is from poetry to uv (a
rust-based python management tool); this approach have some PROS:

* built with rust;
* faster than poetry;
* cleanup some unecessary python dependencies;
* more readable pyproject.toml;
* compatible with python pip install -r approach (for old-school
pythonists).

Until now, a CON is:

* this remove some poetry macros. Still seems like a good replacement.

The folder structure organization allows you to define test suites in
separate folders (e.g. "florestad", "floresta-cli") without needing to
define each of them in pyproject.toml. Files ending with "-test.py" in
each folder will be recognized and executed.

To comply with above mentioned changes, tests/run_tests.py was modified
to inlcude an argument `--test-suite` that will search for a folder
`tests/<test-suite>`. It was also necessary to change `tests/prepare.sh`
and `tests/run.sh` to replace poetry to uv.

The README helps the developer to:

* install uv;
* configure functional test environment;
* format code;
* lint code;
* run tests.

It also updated .gitignore so it can help to avoid add .venv folder that
is created by uv tool.

### Notes to the reviewers

A better context about this change is available in https://github.com/vinteumorg/Floresta/issues/252#issuecomment-2706317274 and https://github.com/vinteumorg/Floresta/pull/391. Tested this approach in https://github.com/qlrd/Floresta/actions/runs/13722793641/job/38381971781

### Checklist

- [x] I've signed all my commits
- [ ] I ran `just lint`
- [ ] I ran `cargo test`
- [x] I've checked the integration tests
- [x] I've followed the [contribution guidelines](https://github.com/vinteumorg/Floresta/blob/master/CONTRIBUTING.md)
- [x] I'm linking the issue being fixed by this PR (if any)



Diff:
diff --git a/.github/workflows/functional.yml b/.github/workflows/functional.yml
index aa130d9b4..63cfa7c8f 100644
--- a/.github/workflows/functional.yml
+++ b/.github/workflows/functional.yml
@@ -13,23 +13,23 @@ jobs:
     steps:
       - uses: actions/checkout@v4
 
-      - name: Install poetry
-        run: pipx install poetry
-
-      - uses: actions/setup-python@v5
+      # see more at
+      # https://docs.astral.sh/uv/guides/integration/github/
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
         with:
           python-version: "3.12"
-          cache: "poetry"
-          cache-dependency-path: "./poetry.lock"
+          enable-cache: true
+          cache-dependency-glob: "uv.lock"
 
       - name: Prepare environment
-        run: poetry install --no-root
+        run: uv sync --all-extras --dev
 
       - name: Run black formatting
-        run: poetry run poe format --check --verbose
+        run: uv run black --check --verbose ./tests
 
       - name: Run pylint linter
-        run: poetry run poe lint --verbose
+        run: uv run pylint --verbose ./tests
 
       - name: Cache Rust
         uses: Swatinem/rust-cache@v2
diff --git a/.gitignore b/.gitignore
index f8b345aac..9dd4a2474 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,9 @@ config.toml
 # IDE configurations
 .idea/
 .vscode/
+
+# uv python management
+.venv
+
+# tests pycache
+tests/**/__pycache__/*
diff --git a/README.md b/README.md
index 2f47aa011..7e7327246 100644
--- a/README.md
+++ b/README.md
@@ -258,53 +258,82 @@ cargo test --release
 
 Additional functional tests are available (minimum python version: 3.12).
 
-* Install [poetry dependencies manager](https://python-poetry.org/docs/#installation). There are many ways to do this:
+* Recommended: install [uv: a rust-based python package and project manager](https://docs.astral.sh/uv/).
+
+* Configure an isolated environment:
 
 ```bash
-# recomended way
-pipx install poetry
+# create a virtual environment
+# (it's good to not mess up with your os)
+uv venv
+
+# Alternatively, you can specify a python version (e.g, 3.12),
+uv venv --python 3.12
+
+# activate the python virtual environment
+source .venv/bin/activate
+
+# check if the python path was modified
+which python
 ```
 
+* Install module dependencies:
+
 ```bash
-# official installer (linux / mac)
-curl -sSL https://install.python-poetry.org | python3 -
-```
+# installs dependencies listed in pyproject.toml.
+# in local development environment
+# it do not remove existing packages.
+uv pip install -r pyproject.toml
+
+# if you're a old-school pythonist,
+# install from requirements.txt
+# without remove existing packages.
+uv pip install -r tests/requirements.txt
 
-```pwsh
-# official isntaller (windows - powershell)
-(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
+# Alternatively, you can synchronize it
+# uses the uv.lock file to enforce
+# reproducible installations.
+uv sync
 ```
 
+* Format code
 ```bash
-# mannually
-python3 -m venv $VENV_PATH
-$VENV_PATH/bin/pip install -U pip setuptools
-$VENV_PATH/bin/pip install poetry
+uv run black ./tests
+
+# if you want to just check
+uv run black --check --verbose ./tests
 ```
 
-* Configure an isolated environment and install module dependencies:
 
+* Lint code
 ```bash
-poetry install --no-root
+uv run pylint ./tests
 ```
 
 * Run tests:
 
+Our tests are separated by "test suites". Suites are folders located in `./tests/<suite>` and the tests are the `./tests/<suite>/*-test.py` files. To run all suites, type:
+
+```bash
+uv run tests/run_tests.py
+```
+
+You can list all suites with:
+
 ```bash
-poetry run poe tests
+uv run tests/run_tests.py --list-suites
 ```
 
-* Before run tests, check the pre-commit:
+To run a specific suite:
 
 ```bash
-poetry run poe pre-commit
+uv run tests/run_tests.py --test-suite <suite>
 ```
 
-* Manual way without poetry: install dependencies and run the test script. This is discouraged since that can lead to inconsistences between different python versions:
+You can even add more:
 
 ```bash
-pip3 install -r tests/requirements.txt
-python tests/run_tests.py
+uv run tests/run_tests.py --test-suite <suite_A> --test-suite <suite_B>
 ```
 
 ## Running Benchmarks
diff --git a/poetry.lock b/poetry.lock
deleted file mode 100644
index 71b12d77f..000000000
--- a/poetry.lock
+++ /dev/null
@@ -1,489 +0,0 @@
-# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
-
-[[package]]
-name = "astroid"
-version = "3.3.6"
-description = "An abstract syntax tree for Python with inference support."
-optional = false
-python-versions = ">=3.9.0"
-files = [
-    {file = "astroid-3.3.6-py3-none-any.whl", hash = "sha256:db676dc4f3ae6bfe31cda227dc60e03438378d7a896aec57422c95634e8d722f"},
-    {file = "astroid-3.3.6.tar.gz", hash = "sha256:6aaea045f938c735ead292204afdb977a36e989522b7833ef6fea94de743f442"},
-]
-
-[[package]]
-name = "black"
-version = "24.10.0"
-description = "The uncompromising code formatter."
-optional = false
-python-versions = ">=3.9"
-files = [
-    {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"},
-    {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"},
-    {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"},
-    {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"},
-    {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"},
-    {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"},
-    {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"},
-    {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"},
-    {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"},
-    {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"},
-    {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"},
-    {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"},
-    {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"},
-    {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"},
-    {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"},
-    {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"},
-    {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"},
-    {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"},
-    {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"},
-    {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"},
-    {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"},
-    {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"},
-]
-
-[package.dependencies]
-click = ">=8.0.0"
-mypy-extensions = ">=0.4.3"
-packaging = ">=22.0"
-pathspec = ">=0.9.0"
-platformdirs = ">=2"
-
-[package.extras]
-colorama = ["colorama (>=0.4.3)"]
-d = ["aiohttp (>=3.10)"]
-jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
-uvloop = ["uvloop (>=0.15.2)"]
-
-[[package]]
-name = "certifi"
-version = "2024.12.14"
-description = "Python package for providing Mozilla's CA Bundle."
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"},
-    {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"},
-]
-
-[[package]]
-name = "charset-normalizer"
-version = "3.4.0"
-description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-optional = false
-python-versions = ">=3.7.0"
-files = [
-    {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"},
-    {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"},
-    {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"},
-    {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"},
-    {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"},
-    {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"},
-    {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"},
-    {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"},
-    {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"},
-    {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"},
-]
-
-[[package]]
-name = "click"
-version = "8.1.7"
-description = "Composable command line interface toolkit"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
-    {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
-]
-
-[package.dependencies]
-colorama = {version = "*", markers = "platform_system == \"Windows\""}
-
-[[package]]
-name = "colorama"
-version = "0.4.6"
-description = "Cross-platform colored terminal text."
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
-files = [
-    {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
-    {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
-]
-
-[[package]]
-name = "dill"
-version = "0.3.9"
-description = "serialize all of Python"
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"},
-    {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"},
-]
-
-[package.extras]
-graph = ["objgraph (>=1.7.2)"]
-profile = ["gprof2dot (>=2022.7.29)"]
-
-[[package]]
-name = "idna"
-version = "3.10"
-description = "Internationalized Domain Names in Applications (IDNA)"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
-    {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
-]
-
-[package.extras]
-all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
-
-[[package]]
-name = "isort"
-version = "5.13.2"
-description = "A Python utility / library to sort Python imports."
-optional = false
-python-versions = ">=3.8.0"
-files = [
-    {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
-    {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
-]
-
-[package.extras]
-colors = ["colorama (>=0.4.6)"]
-
-[[package]]
-name = "jsonrpclib"
-version = "0.2.1"
-description = "Implementation of the JSON-RPC v2.0 specification (backwards-compatible) as a client library."
-optional = false
-python-versions = ">=3.5"
-files = [
-    {file = "jsonrpclib-0.2.1-py3-none-any.whl", hash = "sha256:5a571d3e46fe4f2fe7e607e1732b8a9ad6b7255f53bfbf465822fe1100baf538"},
-    {file = "jsonrpclib-0.2.1.tar.gz", hash = "sha256:8138078fd0f2a5b1df7925e4fa0b82a7c17a4be75bf5634af20463172f44f5c0"},
-]
-
-[[package]]
-name = "mccabe"
-version = "0.7.0"
-description = "McCabe checker, plugin for flake8"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
-    {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
-]
-
-[[package]]
-name = "mypy-extensions"
-version = "1.0.0"
-description = "Type system extensions for programs checked with the mypy type checker."
-optional = false
-python-versions = ">=3.5"
-files = [
-    {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
-    {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
-]
-
-[[package]]
-name = "packaging"
-version = "24.2"
-description = "Core utilities for Python packages"
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
-    {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
-]
-
-[[package]]
-name = "pastel"
-version = "0.2.1"
-description = "Bring colors to your terminal."
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-files = [
-    {file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"},
-    {file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"},
-]
-
-[[package]]
-name = "pathspec"
-version = "0.12.1"
-description = "Utility library for gitignore style pattern matching of file paths."
-optional = false
-python-versions = ">=3.8"
-files = [
-    {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 = "4.3.6"
-description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
-    {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
-]
-
-[package.extras]
-docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"]
-test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
-type = ["mypy (>=1.11.2)"]
-
-[[package]]
-name = "poethepoet"
-version = "0.31.1"
-description = "A task runner that works well with poetry."
-optional = false
-python-versions = ">=3.9"
-files = [
-    {file = "poethepoet-0.31.1-py3-none-any.whl", hash = "sha256:7fdfa0ac6074be9936723e7231b5bfaad2923e96c674a9857e81d326cf8ccdc2"},
-    {file = "poethepoet-0.31.1.tar.gz", hash = "sha256:d6b66074edf85daf115bb916eae0afd6387d19e1562e1c9ef7d61d5c585696aa"},
-]
-
-[package.dependencies]
-pastel = ">=0.2.1,<0.3.0"
-pyyaml = ">=6.0.2,<7.0.0"
-
-[package.extras]
-poetry-plugin = ["poetry (>=1.0,<2.0)"]
-
-[[package]]
-name = "pylint"
-version = "3.3.2"
-description = "python code static checker"
-optional = false
-python-versions = ">=3.9.0"
-files = [
-    {file = "pylint-3.3.2-py3-none-any.whl", hash = "sha256:77f068c287d49b8683cd7c6e624243c74f92890f767f106ffa1ddf3c0a54cb7a"},
-    {file = "pylint-3.3.2.tar.gz", hash = "sha256:9ec054ec992cd05ad30a6df1676229739a73f8feeabf3912c995d17601052b01"},
-]
-
-[package.dependencies]
-astroid = ">=3.3.5,<=3.4.0-dev0"
-colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
-dill = {version = ">=0.3.7", markers = "python_version >= \"3.12\""}
-isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
-mccabe = ">=0.6,<0.8"
-platformdirs = ">=2.2.0"
-tomlkit = ">=0.10.1"
-
-[package.extras]
-spelling = ["pyenchant (>=3.2,<4.0)"]
-testutils = ["gitpython (>3)"]
-
-[[package]]
-name = "pyyaml"
-version = "6.0.2"
-description = "YAML parser and emitter for Python"
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
-    {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
-    {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"},
-    {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"},
-    {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"},
-    {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"},
-    {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"},
-    {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"},
-    {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"},
-    {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"},
-    {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"},
-    {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"},
-    {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"},
-    {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"},
-    {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"},
-    {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"},
-    {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"},
-    {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"},
-    {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"},
-    {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"},
-    {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"},
-    {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"},
-    {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"},
-    {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"},
-    {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"},
-    {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"},
-    {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"},
-    {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"},
-    {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"},
-    {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"},
-    {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"},
-    {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"},
-    {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"},
-    {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"},
-    {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"},
-    {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"},
-    {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"},
-    {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"},
-    {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"},
-    {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"},
-    {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"},
-    {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"},
-    {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"},
-    {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"},
-    {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"},
-    {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"},
-    {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"},
-    {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"},
-    {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"},
-    {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"},
-    {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"},
-    {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"},
-    {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
-]
-
-[[package]]
-name = "requests"
-version = "2.32.3"
-description = "Python HTTP for Humans."
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
-    {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
-]
-
-[package.dependencies]
-certifi = ">=2017.4.17"
-charset-normalizer = ">=2,<4"
-idna = ">=2.5,<4"
-urllib3 = ">=1.21.1,<3"
-
-[package.extras]
-socks = ["PySocks (>=1.5.6,!=1.5.7)"]
-use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
-
-[[package]]
-name = "tomlkit"
-version = "0.13.2"
-description = "Style preserving TOML library"
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"},
-    {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"},
-]
-
-[[package]]
-name = "urllib3"
-version = "2.2.3"
-description = "HTTP library with thread-safe connection pooling, file post, and more."
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"},
-    {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"},
-]
-
-[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
-h2 = ["h2 (>=4,<5)"]
-socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
-zstd = ["zstandard (>=0.18.0)"]
-
-[metadata]
-lock-version = "2.0"
-python-versions = ">=3.12"
-content-hash = "f63036f3ccb0d460bb53ea237079bebf0da82570902757a5cddedf354f98960a"
diff --git a/pyproject.toml b/pyproject.toml
index 5926afa18..8b0590635 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,67 +1,20 @@
-# With this the user can use a custom
-# python environment, like those created
-# with venv or pyenv. The default will be
-# the system python.
-[virtualenvs]
-prefer-active-python = true
-
-# This isn't really needed on pratical aspect
-# since this is only for organize the functional tests
-# but is necessary since its a requirement for poetry.
-[tool.poetry]
+[project]
 name = "floresta-functional-tests"
-version = "0.0.1"
-description = "collection of tools to help with functional testing of Floresta"
-authors = ["The Floresta Project Developers"]
-license = "MIT"
-
-# To add a new dependency, use `poetry add <package>`.
-# To update, first find outdated packages with `poetry show --outdated`,
-# then re-install with `poetry add <package>@<version>`.
-[tool.poetry.dependencies]
-python = ">=3.12"
-jsonrpclib = "^0.2.1"
-requests = "^2.32.3"
-black = "^24.10.0"
-pylint = "^3.3.2"
-poethepoet = "^0.31.1"
-
-# Here we can define some custom tasks
-# (even bash or rust ones can be defined).
-# All of them will run on virtualenv environment.
-# For more information, see guidelines in https://poethepoet.natn.io
-[tool.poe.tasks]
-format = "black ./tests"
-lint = "pylint ./tests"
-example-test = "python tests/run_tests.py --test-name example_test"
-restart-test = "python tests/run_tests.py --test-name restart"
-florestacli-getblockchaininfo-test = "python tests/run_tests.py --test-name floresta_cli_getblockchaininfo"
-florestacli-getblockhash-test = "python tests/run_tests.py --test-name floresta_cli_getblockhash"
-florestacli-getblockheader-test = "python tests/run_tests.py --test-name floresta_cli_getblockheader"
-florestacli-getblock-test = "python tests/run_tests.py --test-name floresta_cli_getblock"
-florestacli-getpeerinfo-test = "python tests/run_tests.py --test-name floresta_cli_getpeerinfo"
-florestacli-addnode-test = "python tests/run_tests.py --test-name floresta_cli_addnode"
-florestacli-stop-test = "python tests/run_tests.py --test-name floresta_cli_stop"
-florestacli-getroots-test = "python tests/run_tests.py --test-name floresta_cli_getroots"
-florestacli-getrpcinfo-test = "python tests/run_tests.py --test-name floresta_cli_getrpcinfo"
-florestacli-getmemoryinfo-test = "python tests/run_tests.py --test-name floresta_cli_getmemoryinfo"
-florestacli-uptime-test = "python tests/run_tests.py --test-name floresta_cli_uptime"
-tests = [
-  "restart-test",
-  "florestacli-getblockchaininfo-test",
-  "florestacli-getblockhash-test",
-  "florestacli-getblockheader-test",
-  "florestacli-getblock-test",
-  "florestacli-getpeerinfo-test",
-  "florestacli-addnode-test",
-  "florestacli-stop-test",
-  "florestacli-getroots-test",
-  "florestacli-getrpcinfo-test",
-  "florestacli-getmemoryinfo-test",
-  "florestacli-uptime-test"
+version = "0.0.2"
+description = "Collection of tools to help with functional testing of Floresta"
+authors = [{name = "The Floresta Project Developers"}]
+license = {text = "MIT"}
+requires-python = ">=3.12"
+dependencies = [
+    "jsonrpclib>=0.2.1",
+    "requests>=2.32.3",
+    "black>=24.10.0",
+    "pylint>=3.3.2",
 ]
-pre-commit = ["format", "lint", "tests"]
+
+[tool.hatch.build.targets.wheel]
+packages = ["tests/test_framework"]
 
 [build-system]
-requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
+requires = ["hatchling"]
+build-backend = "hatchling.build"
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/example_test.py b/tests/example/example-test.py
similarity index 97%
rename from tests/example_test.py
rename to tests/example/example-test.py
index bfe1c5409..d41c5a800 100644
--- a/tests/example_test.py
+++ b/tests/example/example-test.py
@@ -11,19 +11,19 @@
 Any attempt to define a test without these methods will raise a TypeError.
 
 Other methods are available to do more things. Some of them make sense only in `set_test_params`
-and others make sense only in `run_tests`. 
+and others make sense only in `run_tests`.
 
 - `add_node_settings`: register a node settings to create a node after. A node will be a spawned
                        `cargo run --features json-rpc --bin florestad -- --network <chain>` process.
                        In summary, its a `FlorestaRPC` instance.
-                       
+
                        The chain can be one of ["regtest", "signet", "testnet"].
                        You can pass some extra arguments with `extra_args` and it will be appended
                        to the process command. The `rpcserver` is a dictionary defining a "host",
                        "port", "username" and "password". The "data_dir" is optional and can be
                        used to create a temporary directory to store files. It will return an
                        integer pointing an index of a list of nodes.
-                       
+
 - `get_node_settings`: get a registered node settings
 
 - `run_node`: run a node for a registered node settings at some index,
diff --git a/tests/floresta_cli_addnode.py b/tests/floresta-cli/addnode-test.py
similarity index 100%
rename from tests/floresta_cli_addnode.py
rename to tests/floresta-cli/addnode-test.py
diff --git a/tests/floresta_cli_getblock.py b/tests/floresta-cli/getblock-test.py
similarity index 100%
rename from tests/floresta_cli_getblock.py
rename to tests/floresta-cli/getblock-test.py
diff --git a/tests/floresta_cli_getblockchaininfo.py b/tests/floresta-cli/getblockchaininfo-test.py
similarity index 100%
rename from tests/floresta_cli_getblockchaininfo.py
rename to tests/floresta-cli/getblockchaininfo-test.py
diff --git a/tests/floresta_cli_getblockhash.py b/tests/floresta-cli/getblockhash-test.py
similarity index 100%
rename from tests/floresta_cli_getblockhash.py
rename to tests/floresta-cli/getblockhash-test.py
diff --git a/tests/floresta_cli_getblockheader.py b/tests/floresta-cli/getblockheader-test.py
similarity index 100%
rename from tests/floresta_cli_getblockheader.py
rename to tests/floresta-cli/getblockheader-test.py
diff --git a/tests/floresta_cli_getmemoryinfo.py b/tests/floresta-cli/getmemoryinfo-test.py
similarity index 100%
rename from tests/floresta_cli_getmemoryinfo.py
rename to tests/floresta-cli/getmemoryinfo-test.py
diff --git a/tests/floresta_cli_getpeerinfo.py b/tests/floresta-cli/getpeerinfo-test.py
similarity index 100%
rename from tests/floresta_cli_getpeerinfo.py
rename to tests/floresta-cli/getpeerinfo-test.py
diff --git a/tests/floresta_cli_getroots.py b/tests/floresta-cli/getroots-test.py
similarity index 100%
rename from tests/floresta_cli_getroots.py
rename to tests/floresta-cli/getroots-test.py
diff --git a/tests/floresta_cli_getrpcinfo.py b/tests/floresta-cli/getrpcinfo-test.py
similarity index 100%
rename from tests/floresta_cli_getrpcinfo.py
rename to tests/floresta-cli/getrpcinfo-test.py
diff --git a/tests/floresta_cli_stop.py b/tests/floresta-cli/stop-test.py
similarity index 100%
rename from tests/floresta_cli_stop.py
rename to tests/floresta-cli/stop-test.py
diff --git a/tests/floresta_cli_uptime.py b/tests/floresta-cli/uptime-test.py
similarity index 100%
rename from tests/floresta_cli_uptime.py
rename to tests/floresta-cli/uptime-test.py
diff --git a/tests/restart.py b/tests/florestad/restart-test.py
similarity index 100%
rename from tests/restart.py
rename to tests/florestad/restart-test.py
diff --git a/tests/prepare.sh b/tests/prepare.sh
index 3c2cb501a..85ac75597 100755
--- a/tests/prepare.sh
+++ b/tests/prepare.sh
@@ -35,11 +35,11 @@ then
 	exit 1
 fi
 
-poetry -V  &>/dev/null
+uv -V  &>/dev/null
 
 if [ $? -ne 0 ]
 then
-	echo "You must have poetry installed to run those tests!"
+	echo "You must have uv installed to run those tests!"
 	exit 1
 fi
 
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 030c9aabb..5f820ca92 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -1,2 +1,4 @@
-jsonrpclib==0.2.1
-requests==2.32.3
+jsonrpclib>=0.2.1
+requests>=2.32.3
+black>=24.10.0
+pylint>=3.3.2
diff --git a/tests/run.sh b/tests/run.sh
old mode 100644
new mode 100755
index 28034b43b..36b1d4fc5
--- a/tests/run.sh
+++ b/tests/run.sh
@@ -26,6 +26,7 @@ ORIGINAL_PATH=$PATH
 export PATH="$FLORESTA_BIN_DIR:$UTREEXO_BIN_DIR:$PATH"
 
 # Actually runs the tests
-poetry run poe tests
+uv run tests/run_tests.py
+
 # Restores the original PATH
 export PATH=$ORIGINAL_PATH
diff --git a/tests/run_tests.py b/tests/run_tests.py
index a2f50ca2d..f0b6d4ebe 100644
--- a/tests/run_tests.py
+++ b/tests/run_tests.py
@@ -34,9 +34,21 @@
 import argparse
 import tempfile
 
+
 BASE_DIR = os.path.normpath(os.path.join(tempfile.gettempdir(), "floresta-func-tests"))
-SUCCESS_EMOJI = "✔"
+INFO_EMOJI = "ℹ️"
+SUCCESS_EMOJI = "✅"
 FAILURE_EMOJI = "❌"
+ALLDONE_EMOJI = "🎉"
+
+
+def list_test_suites(test_dir: str):
+    """List all test suites inside ./tests"""
+    print(f"{INFO_EMOJI} Available test suites:")
+    for name in os.listdir(test_dir):
+        p = os.path.join(test_dir, name)
+        if os.path.isdir(p) and name not in ("__pycache__", "test_framework"):
+            print(f"* {name}")
 
 
 def main():
@@ -50,7 +62,6 @@ def main():
     options:
         -h, --help                show this help message and exit
         -d, --data-dir DATA_DIR   data directory of the run_tests's functional test logs
-        -t, --test-name TEST_NAME the name of the file to be tested (without .py)
     """
     # Structure the CLI
     parser = argparse.ArgumentParser(
@@ -66,43 +77,99 @@ def main():
     )
 
     parser.add_argument(
-        "-t", "--test-name", help="the name of the file to be tested (without .py)"
+        "-t",
+        "--test-suite",
+        help="test-suit directory to be tested by %(prog)s's. You can add many ",
+        action="append",
+        default=[],
+    )
+
+    parser.add_argument(
+        "-l",
+        "--list-suites",
+        help="list all available test-suit directories to be tested by %(prog)s's",
+        action="store_true",
+        default=False,
     )
 
     # Parse arguments of CLI
     args = parser.parse_args()
 
-    # Define the data-dir and create it
-    data_dir = os.path.normpath(os.path.join(args.data_dir, args.test_name))
-    if not os.path.isdir(data_dir):
-        os.makedirs(data_dir)
-
     # Setup directories and filenames for the specific test
     test_dir = os.path.abspath(os.path.dirname(__file__))
-    test_filename = os.path.normpath(os.path.join(test_dir, f"{args.test_name}.py"))
-    test_logname = os.path.normpath(os.path.join(data_dir, f"{int(time.time())}.log"))
-    print(f"Writing stuff to {test_logname}")
-
-    # Now start the test
-    with open(test_logname, "wt", encoding="utf-8") as log_file:
-        cli = ["python", test_filename]
-        cli_msg = " ".join(cli)
-        print(f"running '{cli_msg}")
-        with subprocess.Popen(cli, stdout=log_file, stderr=log_file) as test:
-            test.wait()
-
-    # Check the test, if failed, log the results
-    # if passed, just show that worked
-    if test.returncode != 0:
-        print(f"Test {args.test_name} not passed {FAILURE_EMOJI}")
-        with open(test_logname, "rt", encoding="utf-8") as log_file:
-            print(log_file.read())
-        raise RuntimeError("Tests failed")
-
-    print(f"Test {args.test_name} passed {SUCCESS_EMOJI}")
-
-    # Add some \n to better visualization on terminal
-    print()
+
+    # if list is provided,
+    # only list the available tests
+    # and exit the program
+    if args.list_suites:
+        list_test_suites(test_dir)
+        return
+
+    # lets define the default paths of suites
+    # in None is provided in CLI.
+    # They should be all folders on tests/ dir,
+    # excluding __pycache__ and test_framework
+    if len(args.test_suite) == 0:
+        for _dir in os.listdir(test_dir):
+            test_suite_dir = os.path.join(test_dir, _dir)
+            if os.path.isdir(test_suite_dir) and _dir not in (
+                "__pycache__",
+                "test_framework",
+            ):
+                args.test_suite.append(test_suite_dir)
+
+    # Run all tests defined by --test_suite if any is (are) provided.
+    # Run all default ones in ./tests/<test-suide-n>/*-test.py
+    for _dir in args.test_suite:
+        test_suite_dir = os.path.join(test_dir, _dir)
+
+        # If a suite isnt defined in tests folder
+        # raise an error and show it to the developer
+        if not os.path.exists(test_suite_dir):
+            raise argparse.ArgumentError(
+                argument=None, message=f"Suite '{_dir}' not found"
+            )
+
+        # If the suite is found, run all tests
+        # inside the folder. The tests should have
+        # a suffix "-test.py"
+        for file in os.listdir(test_suite_dir):
+            if file.endswith("-test.py"):
+
+                # Define the data-dir and create it
+                data_dir = os.path.normpath(os.path.join(args.data_dir, file))
+                if not os.path.isdir(data_dir):
+                    os.makedirs(data_dir)
+
+                # get test file and create a log for it
+                test_filename = os.path.normpath(os.path.join(test_suite_dir, file))
+                test_logname = os.path.normpath(
+                    os.path.join(data_dir, f"{int(time.time())}.log")
+                )
+
+                # Now start the test
+                with open(test_logname, "wt", encoding="utf-8") as log_file:
+                    cli = ["python", test_filename]
+                    cli_msg = " ".join(cli)
+                    print(f"Running '{cli_msg}'")
+
+                    with subprocess.Popen(
+                        cli, stdout=log_file, stderr=log_file
+                    ) as test:
+                        test.wait()
+                        print(f"Writing stuff to {test_logname}")
+
+                # Check the test, if failed, log the results
+                # if passed, just show that worked
+                if test.returncode != 0:
+                    print(f"Test {file} not passed {FAILURE_EMOJI}")
+                    with open(test_logname, "rt", encoding="utf-8") as log_file:
+                        raise RuntimeError(f"Tests failed: {log_file.read()}")
+
+                print(f"Test {file} passed {SUCCESS_EMOJI}")
+                print()
+
+    print("🎉 ALL TESTS PASSED! GOOD JOB!")
 
 
 if __name__ == "__main__":
diff --git a/tests/test_framework/__init__.py b/tests/test_framework/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/test_framework/bitcoin.py b/tests/test_framework/bitcoin.py
index 38a3d7171..66e62b07a 100644
--- a/tests/test_framework/bitcoin.py
+++ b/tests/test_framework/bitcoin.py
@@ -1,5 +1,5 @@
 """
-    General Bitcoin-related tools for our test framework.
+General Bitcoin-related tools for our test framework.
 """
 
 import struct
diff --git a/tests/test_framework/floresta_rpc.py b/tests/test_framework/floresta_rpc.py
index 882b1c2a4..a541ef698 100644
--- a/tests/test_framework/floresta_rpc.py
+++ b/tests/test_framework/floresta_rpc.py
@@ -1,4 +1,4 @@
-""" 
+"""
 floresta_rpc.py
 
 A test framework for testing JsonRPC calls to a floresta node.
@@ -8,7 +8,7 @@
 - get_blockchain_info: `getblochaininfo`;
 - get_blockhash: `getblockhash <height>`;
 - get_block: `getblock <blockhash>`;
-- get_peer_info: `getpeerinfo`; 
+- get_peer_info: `getpeerinfo`;
 - get_stop: `stop`;
 - get_addnode `addnode <ip:port>`;
 - get_roots: `getroots`;
diff --git a/tests/test_framework/key.py b/tests/test_framework/key.py
index 78061fe48..4065d2b99 100644
--- a/tests/test_framework/key.py
+++ b/tests/test_framework/key.py
@@ -9,7 +9,7 @@
 import hashlib
 import hmac
 import random
-from test_framework.crypto import secp256k1
+from tests.test_framework.crypto import secp256k1
 
 # Point with no known discrete log.
 H_POINT = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"
diff --git a/uv.lock b/uv.lock
new file mode 100644
index 000000000..8e5e2c533
--- /dev/null
+++ b/uv.lock
@@ -0,0 +1,252 @@
+version = 1
+revision = 1
+requires-python = ">=3.12"
+
+[[package]]
+name = "astroid"
+version = "3.3.8"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/80/c5/5c83c48bbf547f3dd8b587529db7cf5a265a3368b33e85e76af8ff6061d3/astroid-3.3.8.tar.gz", hash = "sha256:a88c7994f914a4ea8572fac479459f4955eeccc877be3f2d959a33273b0cf40b", size = 398196 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/07/28/0bc8a17d6cd4cc3c79ae41b7105a2b9a327c110e5ddd37a8a27b29a5c8a2/astroid-3.3.8-py3-none-any.whl", hash = "sha256:187ccc0c248bfbba564826c26f070494f7bc964fd286b6d9fff4420e55de828c", size = 275153 },
+]
+
+[[package]]
+name = "black"
+version = "25.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "click" },
+    { name = "mypy-extensions" },
+    { name = "packaging" },
+    { name = "pathspec" },
+    { name = "platformdirs" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988 },
+    { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985 },
+    { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816 },
+    { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860 },
+    { url = "https://files.pythonhosted.org/packages/98/87/0edf98916640efa5d0696e1abb0a8357b52e69e82322628f25bf14d263d1/black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", size = 1650673 },
+    { url = "https://files.pythonhosted.org/packages/52/e5/f7bf17207cf87fa6e9b676576749c6b6ed0d70f179a3d812c997870291c3/black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", size = 1453190 },
+    { url = "https://files.pythonhosted.org/packages/e3/ee/adda3d46d4a9120772fae6de454c8495603c37c4c3b9c60f25b1ab6401fe/black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", size = 1782926 },
+    { url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", size = 1442613 },
+    { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646 },
+]
+
+[[package]]
+name = "certifi"
+version = "2025.1.31"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 },
+]
+
+[[package]]
+name = "charset-normalizer"
+version = "3.4.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 },
+    { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 },
+    { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 },
+    { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 },
+    { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 },
+    { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 },
+    { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 },
+    { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 },
+    { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 },
+    { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 },
+    { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 },
+    { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 },
+    { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 },
+    { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 },
+    { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 },
+    { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 },
+    { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 },
+    { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 },
+    { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 },
+    { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 },
+    { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 },
+    { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 },
+    { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 },
+    { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 },
+    { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 },
+    { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 },
+    { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 },
+]
+
+[[package]]
+name = "click"
+version = "8.1.8"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 },
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
+]
+
+[[package]]
+name = "dill"
+version = "0.3.9"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/70/43/86fe3f9e130c4137b0f1b50784dd70a5087b911fe07fa81e53e0c4c47fea/dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c", size = 187000 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/46/d1/e73b6ad76f0b1fb7f23c35c6d95dbc506a9c8804f43dda8cb5b0fa6331fd/dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a", size = 119418 },
+]
+
+[[package]]
+name = "floresta-functional-tests"
+version = "0.0.2"
+source = { editable = "." }
+dependencies = [
+    { name = "black" },
+    { name = "jsonrpclib" },
+    { name = "pylint" },
+    { name = "requests" },
+]
+
+[package.metadata]
+requires-dist = [
+    { name = "black", specifier = ">=24.10.0" },
+    { name = "jsonrpclib", specifier = ">=0.2.1" },
+    { name = "pylint", specifier = ">=3.3.2" },
+    { name = "requests", specifier = ">=2.32.3" },
+]
+
+[[package]]
+name = "idna"
+version = "3.10"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
+]
+
+[[package]]
+name = "isort"
+version = "6.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b8/21/1e2a441f74a653a144224d7d21afe8f4169e6c7c20bb13aec3a2dc3815e0/isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450", size = 821955 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615", size = 94186 },
+]
+
+[[package]]
+name = "jsonrpclib"
+version = "0.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/55/03/1b8b9f4514a7904c2511448cb04523f3123b31c6cd6ece968dacc8ea100d/jsonrpclib-0.2.1.tar.gz", hash = "sha256:8138078fd0f2a5b1df7925e4fa0b82a7c17a4be75bf5634af20463172f44f5c0", size = 18096 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/2a/7f/e303c32b29ff1ad93b0c106ba148a49006a624e7c8ce65b73f2ff14a4493/jsonrpclib-0.2.1-py3-none-any.whl", hash = "sha256:5a571d3e46fe4f2fe7e607e1732b8a9ad6b7255f53bfbf465822fe1100baf538", size = 15955 },
+]
+
+[[package]]
+name = "mccabe"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350 },
+]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 },
+]
+
+[[package]]
+name = "packaging"
+version = "24.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 },
+]
+
+[[package]]
+name = "pathspec"
+version = "0.12.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 },
+]
+
+[[package]]
+name = "platformdirs"
+version = "4.3.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 },
+]
+
+[[package]]
+name = "pylint"
+version = "3.3.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "astroid" },
+    { name = "colorama", marker = "sys_platform == 'win32'" },
+    { name = "dill" },
+    { name = "isort" },
+    { name = "mccabe" },
+    { name = "platformdirs" },
+    { name = "tomlkit" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ab/b9/50be49afc91469f832c4bf12318ab4abe56ee9aa3700a89aad5359ad195f/pylint-3.3.4.tar.gz", hash = "sha256:74ae7a38b177e69a9b525d0794bd8183820bfa7eb68cc1bee6e8ed22a42be4ce", size = 1518905 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/0d/8b/eef15df5f4e7aa393de31feb96ca9a3d6639669bd59d589d0685d5ef4e62/pylint-3.3.4-py3-none-any.whl", hash = "sha256:289e6a1eb27b453b08436478391a48cd53bb0efb824873f949e709350f3de018", size = 522280 },
+]
+
+[[package]]
+name = "requests"
+version = "2.32.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "certifi" },
+    { name = "charset-normalizer" },
+    { name = "idna" },
+    { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 },
+]
+
+[[package]]
+name = "tomlkit"
+version = "0.13.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b1/09/a439bec5888f00a54b8b9f05fa94d7f901d6735ef4e55dcec9bc37b5d8fa/tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79", size = 192885 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/f9/b6/a447b5e4ec71e13871be01ba81f5dfc9d0af7e473da256ff46bc0e24026f/tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde", size = 37955 },
+]
+
+[[package]]
+name = "urllib3"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 },
+]


Reviews:
user: login: Davidson-Souza
body: `uv` sounds promising, it really is faster than alternatives. If this indeed fixes our nix setup, more than happy to make this change.

Just some minor nits from me. I've ran the tests and works fine
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-10T15:08:57Z
user: login: jaoleal
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-10T15:42:29Z
user: login: jaoleal
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-10T15:48:21Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T16:39:17Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T16:40:22Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T16:47:27Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:56:58Z
user: login: Davidson-Souza
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-10T18:11:11Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T21:07:22Z
user: login: Davidson-Souza
body: ACK [1beb0be](https://github.com/vinteumorg/Floresta/commit/1beb0bed52199a1ee7ecb68291e83be31c969108)
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-10T23:30:37Z
user: login: jaoleal
body: ACK 1beb0bed52199a1ee7ecb68291e83be31c969108
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-12T15:56:49Z

Review comments:
diff_hunk: @@ -258,53 +258,64 @@ cargo test --release
 
 Additional functional tests are available (minimum python version: 3.12).
 
-* Install [poetry dependencies manager](https://python-poetry.org/docs/#installation). There are many ways to do this:
+* Recommended: install [uv: a rust-based python package and project manager](https://docs.astral.sh/uv/).
+
+* Configure an isolated environment:
 
 ```bash
-# recomended way
-pipx install poetry
+# create a virtual environment
+# (it's good to not messing up with your OS)
path: README.md
user: login: Davidson-Souza
body: nit: `it's good to not mess up with your os`
created_at: 2025-03-10T14:58:46Z
author_association: MEMBER
diff_hunk: @@ -258,53 +258,64 @@ cargo test --release
 
 Additional functional tests are available (minimum python version: 3.12).
 
-* Install [poetry dependencies manager](https://python-poetry.org/docs/#installation). There are many ways to do this:
+* Recommended: install [uv: a rust-based python package and project manager](https://docs.astral.sh/uv/).
+
+* Configure an isolated environment:
 
 ```bash
-# recomended way
-pipx install poetry
+# create a virtual environment
+# (it's good to not messing up with your OS)
+uv venv
+
+# Alternatively, you can specify a python version (e.g, 3.12),
+uv venv --python 3.12
+
+# activate the python virtual environment
+source .venv/bin/activate
+
+# check if the python path was modified
+which python
 ```
 
+* Install module dependencies:
+
 ```bash
-# official installer (linux / mac)
-curl -sSL https://install.python-poetry.org | python3 -
-```
+uv pip install -r pyproject.toml
+
+# if you're a old-school pythonist,
+# install from requirements.txt
+uv pip install -r tests/requirements.txt
 
-```pwsh
-# official isntaller (windows - powershell)
-(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
+# Alternatively, you can synchronize it
+uv sync
path: README.md
user: login: Davidson-Souza
body: Isn't `uv pip install -r pyproject.toml` redundant with `uv sync`?
created_at: 2025-03-10T15:03:44Z
author_association: MEMBER
diff_hunk: @@ -258,53 +258,64 @@ cargo test --release
 
 Additional functional tests are available (minimum python version: 3.12).
 
-* Install [poetry dependencies manager](https://python-poetry.org/docs/#installation). There are many ways to do this:
+* Recommended: install [uv: a rust-based python package and project manager](https://docs.astral.sh/uv/).
+
+* Configure an isolated environment:
 
 ```bash
-# recomended way
-pipx install poetry
+# create a virtual environment
+# (it's good to not messing up with your OS)
+uv venv
+
+# Alternatively, you can specify a python version (e.g, 3.12),
+uv venv --python 3.12
+
+# activate the python virtual environment
+source .venv/bin/activate
+
+# check if the python path was modified
+which python
 ```
 
+* Install module dependencies:
+
 ```bash
-# official installer (linux / mac)
-curl -sSL https://install.python-poetry.org | python3 -
-```
+uv pip install -r pyproject.toml
+
+# if you're a old-school pythonist,
+# install from requirements.txt
+uv pip install -r tests/requirements.txt
 
-```pwsh
-# official isntaller (windows - powershell)
-(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
+# Alternatively, you can synchronize it
+uv sync
 ```
 
+* Format code
 ```bash
-# mannually
-python3 -m venv $VENV_PATH
-$VENV_PATH/bin/pip install -U pip setuptools
-$VENV_PATH/bin/pip install poetry
+uv run black ./tests
+
+# if you want to just check
+uv run black --check --verbose ./tests
 ```
 
-* Configure an isolated environment and install module dependencies:
 
+* Lint code
 ```bash
-poetry install --no-root
+uv run pylint ./tests
 ```
 
 * Run tests:
 
-```bash
-poetry run poe tests
-```
-
-* Before run tests, check the pre-commit:
+Our tests are separated by "test suites". The current ones are:
 
-```bash
-poetry run poe pre-commit
-```
+- example (folder `tests/example`);
+- florestad (folder `tests/florestad`);
+- floresta-cli (folder `tests/floresta-cli`).
 
-* Manual way without poetry: install dependencies and run the test script. This is discouraged since that can lead to inconsistences between different python versions:
+All files, inside in those folders, that ends with `*-test.py` will run through this command:
 
 ```bash
-pip3 install -r tests/requirements.txt
-python tests/run_tests.py
+uv run tests/run_tests.py --test-suite <suite>
path: README.md
user: login: Davidson-Souza
body: Add that to run all tests, just omit `--test-suite`.

Also, is there a way to list all available ones?
created_at: 2025-03-10T15:05:26Z
author_association: MEMBER
diff_hunk: @@ -44,9 +44,9 @@
 """
 
 import json
-from test_framework.test_framework import FlorestaTestFramework
-from test_framework.electrum_client import ElectrumClient
-from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from tests.test_framework.test_framework import FlorestaTestFramework
path: tests/example/example-test.py
user: login: Davidson-Souza
body: Isn't there a way to set the root dir to `/tests/`. Not a roadblocker, but a minor annoyance to need this `tests.*`
created_at: 2025-03-10T15:07:11Z
author_association: MEMBER
diff_hunk: @@ -258,53 +258,64 @@ cargo test --release
 
 Additional functional tests are available (minimum python version: 3.12).
 
-* Install [poetry dependencies manager](https://python-poetry.org/docs/#installation). There are many ways to do this:
+* Recommended: install [uv: a rust-based python package and project manager](https://docs.astral.sh/uv/).
+
+* Configure an isolated environment:
 
 ```bash
-# recomended way
-pipx install poetry
+# create a virtual environment
+# (it's good to not messing up with your OS)
+uv venv
+
+# Alternatively, you can specify a python version (e.g, 3.12),
+uv venv --python 3.12
+
+# activate the python virtual environment
+source .venv/bin/activate
+
+# check if the python path was modified
+which python
 ```
 
+* Install module dependencies:
+
 ```bash
-# official installer (linux / mac)
-curl -sSL https://install.python-poetry.org | python3 -
-```
+uv pip install -r pyproject.toml
+
+# if you're a old-school pythonist,
+# install from requirements.txt
+uv pip install -r tests/requirements.txt
 
-```pwsh
-# official isntaller (windows - powershell)
-(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
+# Alternatively, you can synchronize it
+uv sync
 ```
 
+* Format code
 ```bash
-# mannually
-python3 -m venv $VENV_PATH
-$VENV_PATH/bin/pip install -U pip setuptools
-$VENV_PATH/bin/pip install poetry
+uv run black ./tests
+
+# if you want to just check
+uv run black --check --verbose ./tests
 ```
 
-* Configure an isolated environment and install module dependencies:
 
+* Lint code
 ```bash
-poetry install --no-root
+uv run pylint ./tests
 ```
 
 * Run tests:
 
-```bash
-poetry run poe tests
-```
-
-* Before run tests, check the pre-commit:
+Our tests are separated by "test suites". The current ones are:
 
-```bash
-poetry run poe pre-commit
-```
+- example (folder `tests/example`);
+- florestad (folder `tests/florestad`);
+- floresta-cli (folder `tests/floresta-cli`).
 
-* Manual way without poetry: install dependencies and run the test script. This is discouraged since that can lead to inconsistences between different python versions:
+All files, inside in those folders, that ends with `*-test.py` will run through this command:
 
 ```bash
-pip3 install -r tests/requirements.txt
-python tests/run_tests.py
+uv run tests/run_tests.py --test-suite <suite>
path: README.md
user: login: jaoleal
body: I made the same suggestion to @qlrd while he was at casavinteum. And looks like he already implemented.

When tests.py are invoked without `-t` or `--test-suite` set, it computes every subfolder of `tests/` as a suite. `test_framework` isnt added as suite.

See https://github.com/vinteumorg/Floresta/pull/402/files#diff-88fd88a13f19bfeedc205c137e4fa94c7cd34be808ad01dab5e5d69641e60e0cR57
created_at: 2025-03-10T15:42:29Z
author_association: MEMBER
diff_hunk: @@ -258,53 +258,64 @@ cargo test --release
 
 Additional functional tests are available (minimum python version: 3.12).
 
-* Install [poetry dependencies manager](https://python-poetry.org/docs/#installation). There are many ways to do this:
+* Recommended: install [uv: a rust-based python package and project manager](https://docs.astral.sh/uv/).
+
+* Configure an isolated environment:
 
 ```bash
-# recomended way
-pipx install poetry
+# create a virtual environment
+# (it's good to not messing up with your OS)
+uv venv
+
+# Alternatively, you can specify a python version (e.g, 3.12),
+uv venv --python 3.12
+
+# activate the python virtual environment
+source .venv/bin/activate
+
+# check if the python path was modified
+which python
 ```
 
+* Install module dependencies:
+
 ```bash
-# official installer (linux / mac)
-curl -sSL https://install.python-poetry.org | python3 -
-```
+uv pip install -r pyproject.toml
+
+# if you're a old-school pythonist,
+# install from requirements.txt
+uv pip install -r tests/requirements.txt
 
-```pwsh
-# official isntaller (windows - powershell)
-(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
+# Alternatively, you can synchronize it
+uv sync
 ```
 
+* Format code
 ```bash
-# mannually
-python3 -m venv $VENV_PATH
-$VENV_PATH/bin/pip install -U pip setuptools
-$VENV_PATH/bin/pip install poetry
+uv run black ./tests
+
+# if you want to just check
+uv run black --check --verbose ./tests
 ```
 
-* Configure an isolated environment and install module dependencies:
 
+* Lint code
 ```bash
-poetry install --no-root
+uv run pylint ./tests
 ```
 
 * Run tests:
 
-```bash
-poetry run poe tests
-```
-
-* Before run tests, check the pre-commit:
+Our tests are separated by "test suites". The current ones are:
 
-```bash
-poetry run poe pre-commit
-```
+- example (folder `tests/example`);
+- florestad (folder `tests/florestad`);
+- floresta-cli (folder `tests/floresta-cli`).
 
-* Manual way without poetry: install dependencies and run the test script. This is discouraged since that can lead to inconsistences between different python versions:
+All files, inside in those folders, that ends with `*-test.py` will run through this command:
 
 ```bash
-pip3 install -r tests/requirements.txt
-python tests/run_tests.py
+uv run tests/run_tests.py --test-suite <suite>
path: README.md
user: login: jaoleal
body: i agree with davidson, a `uv run tests/run_tests.py --list-suites` would be nice, one that is debugging our python tests can use this command to undersand what `run_tests.py` see as a suite.
created_at: 2025-03-10T15:48:21Z
author_association: MEMBER
diff_hunk: @@ -258,53 +258,64 @@ cargo test --release
 
 Additional functional tests are available (minimum python version: 3.12).
 
-* Install [poetry dependencies manager](https://python-poetry.org/docs/#installation). There are many ways to do this:
+* Recommended: install [uv: a rust-based python package and project manager](https://docs.astral.sh/uv/).
+
+* Configure an isolated environment:
 
 ```bash
-# recomended way
-pipx install poetry
+# create a virtual environment
+# (it's good to not messing up with your OS)
+uv venv
+
+# Alternatively, you can specify a python version (e.g, 3.12),
+uv venv --python 3.12
+
+# activate the python virtual environment
+source .venv/bin/activate
+
+# check if the python path was modified
+which python
 ```
 
+* Install module dependencies:
+
 ```bash
-# official installer (linux / mac)
-curl -sSL https://install.python-poetry.org | python3 -
-```
+uv pip install -r pyproject.toml
+
+# if you're a old-school pythonist,
+# install from requirements.txt
+uv pip install -r tests/requirements.txt
 
-```pwsh
-# official isntaller (windows - powershell)
-(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
+# Alternatively, you can synchronize it
+uv sync
 ```
 
+* Format code
 ```bash
-# mannually
-python3 -m venv $VENV_PATH
-$VENV_PATH/bin/pip install -U pip setuptools
-$VENV_PATH/bin/pip install poetry
+uv run black ./tests
+
+# if you want to just check
+uv run black --check --verbose ./tests
 ```
 
-* Configure an isolated environment and install module dependencies:
 
+* Lint code
 ```bash
-poetry install --no-root
+uv run pylint ./tests
 ```
 
 * Run tests:
 
-```bash
-poetry run poe tests
-```
-
-* Before run tests, check the pre-commit:
+Our tests are separated by "test suites". The current ones are:
 
-```bash
-poetry run poe pre-commit
-```
+- example (folder `tests/example`);
+- florestad (folder `tests/florestad`);
+- floresta-cli (folder `tests/floresta-cli`).
 
-* Manual way without poetry: install dependencies and run the test script. This is discouraged since that can lead to inconsistences between different python versions:
+All files, inside in those folders, that ends with `*-test.py` will run through this command:
 
 ```bash
-pip3 install -r tests/requirements.txt
-python tests/run_tests.py
+uv run tests/run_tests.py --test-suite <suite>
path: README.md
user: login: qlrd
body: Sure! 

@jaoleal, i improved it and i think is more clear. I added here a --list-suite and will do a rebase.
created_at: 2025-03-10T16:39:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -44,9 +44,9 @@
 """
 
 import json
-from test_framework.test_framework import FlorestaTestFramework
-from test_framework.electrum_client import ElectrumClient
-from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from tests.test_framework.test_framework import FlorestaTestFramework
path: tests/example/example-test.py
user: login: qlrd
body: Not sure, i will need try here @Davidson-Souza.
created_at: 2025-03-10T16:40:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -258,53 +258,64 @@ cargo test --release
 
 Additional functional tests are available (minimum python version: 3.12).
 
-* Install [poetry dependencies manager](https://python-poetry.org/docs/#installation). There are many ways to do this:
+* Recommended: install [uv: a rust-based python package and project manager](https://docs.astral.sh/uv/).
+
+* Configure an isolated environment:
 
 ```bash
-# recomended way
-pipx install poetry
+# create a virtual environment
+# (it's good to not messing up with your OS)
+uv venv
+
+# Alternatively, you can specify a python version (e.g, 3.12),
+uv venv --python 3.12
+
+# activate the python virtual environment
+source .venv/bin/activate
+
+# check if the python path was modified
+which python
 ```
 
+* Install module dependencies:
+
 ```bash
-# official installer (linux / mac)
-curl -sSL https://install.python-poetry.org | python3 -
-```
+uv pip install -r pyproject.toml
+
+# if you're a old-school pythonist,
+# install from requirements.txt
+uv pip install -r tests/requirements.txt
 
-```pwsh
-# official isntaller (windows - powershell)
-(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
+# Alternatively, you can synchronize it
+uv sync
path: README.md
user: login: qlrd
body: From what i understood in docs:

* [`uv pip install -r pyproject.toml`](https://docs.astral.sh/uv/reference/cli/#uv-pip-install) installs dependencies listed in `pyproject.toml` (in local development environment, it do not remove existing packages).

* [`uv sync`](https://docs.astral.sh/uv/reference/cli/#uv-sync) uses the `uv.lock` file to enforce reproducible installations.

So the `sync` reproduced what i made here. Maybe it's better add this warning?

created_at: 2025-03-10T16:47:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -44,9 +44,9 @@
 """
 
 import json
-from test_framework.test_framework import FlorestaTestFramework
-from test_framework.electrum_client import ElectrumClient
-from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from tests.test_framework.test_framework import FlorestaTestFramework
path: tests/example/example-test.py
user: login: qlrd
body: fixed
created_at: 2025-03-10T17:56:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -258,53 +258,64 @@ cargo test --release
 
 Additional functional tests are available (minimum python version: 3.12).
 
-* Install [poetry dependencies manager](https://python-poetry.org/docs/#installation). There are many ways to do this:
+* Recommended: install [uv: a rust-based python package and project manager](https://docs.astral.sh/uv/).
+
+* Configure an isolated environment:
 
 ```bash
-# recomended way
-pipx install poetry
+# create a virtual environment
+# (it's good to not messing up with your OS)
+uv venv
+
+# Alternatively, you can specify a python version (e.g, 3.12),
+uv venv --python 3.12
+
+# activate the python virtual environment
+source .venv/bin/activate
+
+# check if the python path was modified
+which python
 ```
 
+* Install module dependencies:
+
 ```bash
-# official installer (linux / mac)
-curl -sSL https://install.python-poetry.org | python3 -
-```
+uv pip install -r pyproject.toml
+
+# if you're a old-school pythonist,
+# install from requirements.txt
+uv pip install -r tests/requirements.txt
 
-```pwsh
-# official isntaller (windows - powershell)
-(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
+# Alternatively, you can synchronize it
+uv sync
path: README.md
user: login: Davidson-Souza
body: Hmm, so they aren't the exact same thing.

> Maybe it's better add this warning?

Yeah, I think some docs about the difference should be enough.
created_at: 2025-03-10T18:11:11Z
author_association: MEMBER
diff_hunk: @@ -258,53 +258,64 @@ cargo test --release
 
 Additional functional tests are available (minimum python version: 3.12).
 
-* Install [poetry dependencies manager](https://python-poetry.org/docs/#installation). There are many ways to do this:
+* Recommended: install [uv: a rust-based python package and project manager](https://docs.astral.sh/uv/).
+
+* Configure an isolated environment:
 
 ```bash
-# recomended way
-pipx install poetry
+# create a virtual environment
+# (it's good to not messing up with your OS)
+uv venv
+
+# Alternatively, you can specify a python version (e.g, 3.12),
+uv venv --python 3.12
+
+# activate the python virtual environment
+source .venv/bin/activate
+
+# check if the python path was modified
+which python
 ```
 
+* Install module dependencies:
+
 ```bash
-# official installer (linux / mac)
-curl -sSL https://install.python-poetry.org | python3 -
-```
+uv pip install -r pyproject.toml
+
+# if you're a old-school pythonist,
+# install from requirements.txt
+uv pip install -r tests/requirements.txt
 
-```pwsh
-# official isntaller (windows - powershell)
-(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
+# Alternatively, you can synchronize it
+uv sync
path: README.md
user: login: qlrd
body: Added some comments with almost same phrases above the commands.
created_at: 2025-03-10T21:07:22Z
author_association: CONTRIBUTOR

PR comments:
user: login: jaoleal
created_at: 2025-03-11T21:01:21Z
body: Im up with the changes but, before acking this i have to ask @Davidson-Souza about some CI logic that this Pr implies along with the changes needed for #391.

Should linting and formatting fail the test execution ? Youll see the commands to check lint and formatting are included in CI but outside `prepare.sh` and `run.sh`. 


author_association: MEMBER
user: login: qlrd
created_at: 2025-03-11T22:42:43Z
body: > Should linting and formatting fail the test execution ? Youll see the commands to check lint and formatting are included in CI but outside `prepare.sh` and `run.sh`.

This make sense in another workflow, as another checker, triggered before the `functional.yml` (like a `lint-functional.yml`), i.e, if the functional tests is not well formatted, don't make sense to run functional tests neither build floresta. 

If it pass, go to `functional.yml` and anothers.


author_association: CONTRIBUTOR
user: login: Davidson-Souza
created_at: 2025-03-11T23:33:38Z
body: > Should linting and formatting fail the test execution ?

It should break CI. Perhaps getting the python lint check inside our `linting` task?
author_association: MEMBER
user: login: qlrd
created_at: 2025-03-12T11:51:15Z
body: > > Should linting and formatting fail the test execution ?
> 
> It should break CI. Perhaps getting the python lint check inside our `linting` task?

Maybe it will break CI regardless of where it is run if we don't do something like:

```yaml
# .github/workflows/rust.yml
jobs:
  linting:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      
      - name: Install uv
        uses: astral-sh/setup-uv@v5
        with:
          python-version: "3.12"
          enable-cache: true
          cache-dependency-glob: "uv.lock"

      - name: Prepare environment
        run: uv sync --all-extras --dev

      - name: Run black formatting
        continue-on-error: true # <----------------
        run: uv run black --check --verbose ./tests

      - name: Run pylint linter
        continue-on-error: true # <----------------
        run: uv run pylint --verbose ./tests

      - name: Install latest nightly
        uses: dtolnay/rust-toolchain@nightly
        with:
          components: rustfmt, clippy

      - name: Run cargo fmt
        run: cargo +nightly fmt --all --check

      - name: Run cargo clippy
        run: cargo +nightly clippy --all-targets -- -D warnings
```

This could be applied on `functional.yml` too, but with another step with a `if: failure()`, checking if the format/lint check failed and give some [warning](https://github.com/marketplace/actions/comment-pull-request), or something similar, like a PR automated comment (but it will require some [permission access](https://github.com/marketplace/actions/comment-pull-request#permissions))?

```yaml
    - name: Run black formatting
      continue-on-error: true # <----------------
      run: uv run black --check --verbose ./tests

    - name: Comment on PR if black failed
      if: failure()
      uses: thollander/actions-comment-pull-request@v3
        with:
          message: |
            ...
```
author_association: CONTRIBUTOR
user: login: Davidson-Souza
created_at: 2025-03-12T14:10:14Z
body: > Maybe it will break CI regardless of where it is run if we don't do something like:

Yeah, the current way it will break. No reason to change IMO
author_association: MEMBER
user: login: jaoleal
created_at: 2025-03-12T15:55:19Z
body: >No reason to change IMO

Okie Dokie
author_association: MEMBER