From 3b43b790856996de19a207f9540aee0de08f5e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Thu, 23 Feb 2023 17:49:40 +0100 Subject: [PATCH 01/26] feat: setup repo --- .flake8 | 8 ++ .gitignore | 162 ++++++++++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 58 ++++++++++++++ README.md | 88 ++++++++++++++++++++++ examples/mirror.py | 23 ++++++ pyproject.toml | 51 +++++++++++++ 6 files changed, 390 insertions(+) create mode 100644 .flake8 create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 README.md create mode 100644 examples/mirror.py create mode 100644 pyproject.toml diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..ec7088b --- /dev/null +++ b/.flake8 @@ -0,0 +1,8 @@ +[flake8] +per-file-ignores = + **/__init__.py: F401 +extend-ignore = + # See: https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html + E203, +# Commented Black formatted code +max-line-length = 89 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e277343 --- /dev/null +++ b/.gitignore @@ -0,0 +1,162 @@ +# Reference: https://github.com/github/gitignore/blob/main/Python.gitignore + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9c90beb --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,58 @@ +--- +ci: + # Can't use a local installation of pylint with pre-commit.ci + skip: [pylint] + +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +default_language_version: + python: python3.10 +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - repo: https://github.com/psf/black + rev: 23.1.0 + hooks: + - id: black + args: [--safe, --quiet] + - repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + name: isort (python) + - repo: local + hooks: + - id: pylint + name: pylint + entry: pylint + language: system + types: [python] + # TODO: change this on GitHub + args: [-rn, -sn, --rcfile=python/pyproject.toml] + - repo: https://github.com/pycqa/flake8 + rev: 6.0.0 + hooks: + - id: flake8 + args: [--config=python/.flake8] + - repo: https://github.com/pycqa/pydocstyle + rev: 6.3.0 + hooks: + - id: pydocstyle + additional_dependencies: + - tomli # for reading config from pyproject.toml + # - repo: https://github.com/pre-commit/mirrors-mypy + # rev: v1.0.0 + # hooks: + # - id: mypy + # additional_dependencies: + # - typing_extensions + - repo: https://github.com/Lucas-C/pre-commit-hooks-bandit + rev: v1.0.6 + hooks: + - id: python-bandit-vulnerability-check + args: [--skip, B101, --recursive, clumper] diff --git a/README.md b/README.md new file mode 100644 index 0000000..00088a0 --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +# Serverless Functions Python 💜 + +Scaleway Serverless Functions is a framework to provide a good developer experience to write Serverless Functions. + +Serverless Functions make it easy to deploy, scale, and optimize your workloads on the cloud. + +Get started with Scaleway Functions (we support multiple languages :rocket:): + +- [Scaleway Serverless Functions Documentation](https://www.scaleway.com/en/docs/serverless/functions/quickstart/) +- [Scaleway Serverless Framework plugin](https://github.com/scaleway/serverless-scaleway-functions) +- [Scaleway Serverless Examples](https://github.com/scaleway/serverless-examples) +- [Scaleway Cloud Provider](https://scaleway.com) + +Testing frameworks for Scaleway Serverless Functions in other languages can be found here: + +- [Node](https://github.com/scaleway/serverless-functions-node) +- [Go](https://github.com/scaleway/serverless-functions-go) +- [PHP](https://github.com/scaleway/serverless-functions-php) +- [Rust](https://github.com/scaleway/serverless-functions-rust) + +## 🚀 Features + +This repository aims to provide the best experience: **local testing, utils, documentation etc...** +additionally we love to share things with the community and we want to expose receipts to the public. That's why we make our framework publicly available to help the community! + +## 🏡 Local testing + +What this package does: + +- **Format Input**: FaaS have a specific input format encapsulating the body received by functions to add some useful data. + The local testing package lets you interact with this data. +- **Advanced debugging**: To improve developer experience you can run your handler locally, on your computer to make + it simpler to debug by running your code step-by-step or reading output directly before deploying it. + +What this package does not: + +- **Build functions**: When your function is uploaded we build it in an environment that can be different than yours. Our build pipelines support + tons of different packages but sometimes it requires a specific setup, for example, if your function requires a specific 3D system library. +If you have compatibility issues, please see the help section. + +## 🛟 Help & support + +- Scaleway support is available on Scaleway Console. +- Additionally, you can join our [Slack Community](https://www.scaleway.com/en/docs/tutorials/scaleway-slack-community/) + +## 🎓 Contributing + +We welcome all contributions to our open-source projects, please see our contributing guidelines . + +Do not hesitate to raise issues and pull requests we will have a look at them. + +## Usage + +```python +from serverless_functions_python import serve_handler_locally + +def handler(event, context): + return "Hello World!" + +if __name__ == "__main__": + serve_handler_locally(handler) +``` + +This file will expose your handler on a local web server allowing you to test your function. + +Some information will be added to requests for example specific headers. For local development, additional header values are hardcoded +to make it easy to differentiate them. In production, you will be able to observe headers with exploitable data. + +Local testing part of this framework does not aim to simulate 100% production but it aims to make it easier to work with functions locally. + +## ❓ FAQ + +**Why do I need an additional package to call my function?** + +Your Function Handler can be served by a simple HTTP server but Serverless Ecosystem involves a lot of different layers +and this package aims to simulate everything your request will go through. + +**How my function will be deployed** + +Your function will be deployed in an environment that allows your function to easily Scale up and down and it's wrapped into +different pieces of software with different roles. This stack also changes the headers, input and output of your function, that's why +this tool has been developed to simulate this part. + +**Do I need to deploy my function differently?** + +No. This framework does not affect deployment or performance. + +## 🏛️ Architecture \ No newline at end of file diff --git a/examples/mirror.py b/examples/mirror.py new file mode 100644 index 0000000..b1615a6 --- /dev/null +++ b/examples/mirror.py @@ -0,0 +1,23 @@ +import json +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from serverless_functions_python import Context, Event, Response + + +def handler(event: "Event", context: "Context") -> "Response": + """Function that mirrors its parameters in the body.""" + return { + "body": json.dumps( + { + "event": event, + "context": context, + } + ) + } + + +if __name__ == "__main__": + from serverless_functions_python import serve_handler_locally + + serve_handler_locally(handler) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..963423c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,51 @@ +[tool.poetry] +name = "serverless-functions-python" +version = "0.1.0" +description = "" +authors = ["Scaleway Serverless Team "] +readme = "README.md" +packages = [{ include = "serverless_functions_python", from = "src" }] + +[tool.poetry.dependencies] +python = "^3.10" +flask = "^2.2.2" +typing-extensions = { version = "^4.4.0", python = "<3.11" } + +[tool.poetry.group.dev.dependencies] +autoflake = "^1.7.7" +black = "^23.01.0" +flake8 = "^6.0.0" +isort = "^5.10.1" +pre-commit = "^3.0.4" +pylint = "^2.16.2" +pylint-per-file-ignores = "^1.2.0" +pytest = "^7.2.1" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.pytest.ini_options] +# addopts = ["--import-mode=importlib"] +pythonpath = ["src"] +testpaths = ["tests"] + +[tool.pylint] +load-plugins = ["pylint_per_file_ignores"] +disable = "missing-module-docstring" +# Commented Black formatted code. +max-line-length = 89 +# Short and common names. e is commonly used for exceptions. +good-names = "i,fp,e" + +[tool.pylint-per-file-ignores] +# Redfined outer name is for pytest fixtures +"/tests/" = "missing-class-docstring,missing-function-docstring,protected-access,redefined-outer-name" + +[tool.isort] +profile = "black" + +[tool.pydocstyle] +# Compatible with Sphinx +convention = "google" +add_ignore = ["D100", "D104", "D107"] From 0f0d4a79cc5a1afcd9523c708521842040a02a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Thu, 23 Feb 2023 18:00:02 +0100 Subject: [PATCH 02/26] feat: add missing files to repo --- .github/dependabot.yml | 12 ++++++++++++ CHANGELOG.md | 14 ++++++++++++++ LICENSE | 21 +++++++++++++++++++++ pyproject.toml | 27 +++++++++++++++++++++++++-- 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 CHANGELOG.md create mode 100644 LICENSE diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8b00cbb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + # Workflow files stored in the + # default location of `.github/workflows` + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..928e135 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +All notable changes to this project will be documented in this file. + + + +## [Unreleased] + +### Added + +- Initial project setup +- Local testing utils + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2421498 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Scaleway + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pyproject.toml b/pyproject.toml index 963423c..dcf49f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,34 @@ [tool.poetry] name = "serverless-functions-python" version = "0.1.0" -description = "" +description = "Framework to provide a good developer experience when writing Serverless Functions in Python." authors = ["Scaleway Serverless Team "] + readme = "README.md" +license = "MIT" +repository = "https://github.com/scaleway/serverless-functions-python" + +keywords = ["serverless", "scaleway", "functions", "cloud", "faas"] + +# Should be one of: +# "Development Status :: 3 - Alpha" +# "Development Status :: 4 - Beta" +# "Development Status :: 5 - Production/Stable" +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Intended Audience :: Information Technology", + "Topic :: Software Development :: Libraries :: Application Frameworks", + "Topic :: Internet", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] + packages = [{ include = "serverless_functions_python", from = "src" }] +include = ["CHANGELOG.md"] [tool.poetry.dependencies] python = "^3.10" @@ -26,7 +50,6 @@ requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.pytest.ini_options] -# addopts = ["--import-mode=importlib"] pythonpath = ["src"] testpaths = ["tests"] From 3555f0bb57a1279477951cd9b3392e13df9f472d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 16:24:44 +0100 Subject: [PATCH 03/26] chore: some cleanup --- .pre-commit-config.yaml | 12 ++++++------ CHANGELOG.md | 3 +-- README.md | 8 ++++---- pyproject.toml | 5 ++++- src/framework/__init__.py | 0 src/testing/__init__.py | 0 6 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 src/framework/__init__.py create mode 100644 src/testing/__init__.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9c90beb..1870af9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,12 +45,12 @@ repos: - id: pydocstyle additional_dependencies: - tomli # for reading config from pyproject.toml - # - repo: https://github.com/pre-commit/mirrors-mypy - # rev: v1.0.0 - # hooks: - # - id: mypy - # additional_dependencies: - # - typing_extensions + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.0.0 + hooks: + - id: mypy + additional_dependencies: + - typing_extensions - repo: https://github.com/Lucas-C/pre-commit-hooks-bandit rev: v1.0.6 hooks: diff --git a/CHANGELOG.md b/CHANGELOG.md index 928e135..c8eff3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -### Added +### Added - Initial project setup - Local testing utils - diff --git a/README.md b/README.md index 00088a0..0a9d474 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ Do not hesitate to raise issues and pull requests we will have a look at them. ## Usage +Here's how you can get started with the framework: + ```python from serverless_functions_python import serve_handler_locally @@ -58,10 +60,10 @@ def handler(event, context): return "Hello World!" if __name__ == "__main__": - serve_handler_locally(handler) + serve_handler_locally(handler, port=8080) ``` -This file will expose your handler on a local web server allowing you to test your function. +This will expose your handler on a local web server allowing you to test your function. Some information will be added to requests for example specific headers. For local development, additional header values are hardcoded to make it easy to differentiate them. In production, you will be able to observe headers with exploitable data. @@ -84,5 +86,3 @@ this tool has been developed to simulate this part. **Do I need to deploy my function differently?** No. This framework does not affect deployment or performance. - -## 🏛️ Architecture \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index dcf49f4..ac68c2a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,10 @@ classifiers = [ "Programming Language :: Python :: 3.11", ] -packages = [{ include = "serverless_functions_python", from = "src" }] +packages = [ + { include = "framework", from = "src" }, + { include = "testing", from = "src" }, +] include = ["CHANGELOG.md"] [tool.poetry.dependencies] diff --git a/src/framework/__init__.py b/src/framework/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/testing/__init__.py b/src/testing/__init__.py new file mode 100644 index 0000000..e69de29 From 8ec6a23255f4f40273f6832bc8d8ba8b9111bdcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 16:55:18 +0100 Subject: [PATCH 04/26] ci: initial commit --- .github/actions/setup-poetry/action.yml | 33 + .github/workflows/pytest.yml | 35 + .github/workflows/python-publish.yml | 33 + poetry.lock | 935 ++++++++++++++++++++++++ pyproject.toml | 1 + tests/__init__.py | 0 tests/test_fake.py | 2 + 7 files changed, 1039 insertions(+) create mode 100644 .github/actions/setup-poetry/action.yml create mode 100644 .github/workflows/pytest.yml create mode 100644 .github/workflows/python-publish.yml create mode 100644 poetry.lock create mode 100644 tests/__init__.py create mode 100644 tests/test_fake.py diff --git a/.github/actions/setup-poetry/action.yml b/.github/actions/setup-poetry/action.yml new file mode 100644 index 0000000..fa96460 --- /dev/null +++ b/.github/actions/setup-poetry/action.yml @@ -0,0 +1,33 @@ +name: Set up poetry +description: Install poetry and python dependencies +inputs: + groups: + description: "Poetry groups." + required: false + default: "dev" +runs: + using: "composite" + steps: + - name: Install bash and curl + shell: sh + run: | + apk update + apk add --no-cache bash curl + + - uses: snok/install-poetry@v1 + with: + version: 1.3.2 + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Cache poetry dependencies + id: cache-poetry-deps + uses: actions/cache@v3 + with: + path: .venv + key: pydeps-${{ hashFiles('**/poetry.lock') }}-${{ github.event.inputs.groups }} + + - name: Install poetry dependencies + shell: bash + run: poetry install --no-interaction --no-root --with=${{ github.event.inputs.groups }} + if: steps.cache-deps.outputs.cache-hit != 'true' diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml new file mode 100644 index 0000000..3fd8cfa --- /dev/null +++ b/.github/workflows/pytest.yml @@ -0,0 +1,35 @@ +name: Pytest + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +permissions: + contents: read + +jobs: + test: + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11"] + + runs-on: self-hosted + container: python:{{ matrix.python-version }}-alpine + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup-poetry + + - name: Test with pytest + working-directory: tests + run: poetry run pytest tests --junitxml=junit/test-results-${{ matrix.python-version }}.xml + + - name: Upload pytest test results + uses: actions/upload-artifact@v3 + with: + name: pytest-results-${{ matrix.python-version }} + path: junit/test-results-${{ matrix.python-version }}.xml + # Use always() to always run this step to publish test results when there are test failures + if: ${{ always() }} diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..06909ea --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,33 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + deploy: + runs-on: self-hosted + container: python:3.11-alpine + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup-poetry + with: + groups: "" + + - name: Publish package + run: poetry publish --build + env: + POETRY_HTTP_BASIC_PYPI_USERNAME: __token__ + POETRY_HTTP_BASIC_PYPI_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..a3d5993 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,935 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + +[[package]] +name = "astroid" +version = "2.14.2" +description = "An abstract syntax tree for Python with inference support." +category = "dev" +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "astroid-2.14.2-py3-none-any.whl", hash = "sha256:0e0e3709d64fbffd3037e4ff403580550f14471fd3eaae9fa11cc9a5c7901153"}, + {file = "astroid-2.14.2.tar.gz", hash = "sha256:a3cf9f02c53dd259144a7e8f3ccd75d67c9a8c716ef183e0c1f291bc5d7bb3cf"}, +] + +[package.dependencies] +lazy-object-proxy = ">=1.4.0" +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} +wrapt = [ + {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, +] + +[[package]] +name = "attrs" +version = "22.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, + {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] +tests = ["attrs[tests-no-zope]", "zope.interface"] +tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] + +[[package]] +name = "autoflake" +version = "1.7.7" +description = "Removes unused imports and unused variables" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "autoflake-1.7.7-py3-none-any.whl", hash = "sha256:a9b43d08f8e455824e4f7b3f078399f59ba538ba53872f466c09e55c827773ef"}, + {file = "autoflake-1.7.7.tar.gz", hash = "sha256:c8e4fc41aa3eae0f5c94b939e3a3d50923d7a9306786a6cbf4866a077b8f6832"}, +] + +[package.dependencies] +pyflakes = ">=1.1.0" +tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} + +[[package]] +name = "black" +version = "23.1.0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "black-23.1.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:b6a92a41ee34b883b359998f0c8e6eb8e99803aa8bf3123bf2b2e6fec505a221"}, + {file = "black-23.1.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:57c18c5165c1dbe291d5306e53fb3988122890e57bd9b3dcb75f967f13411a26"}, + {file = "black-23.1.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:9880d7d419bb7e709b37e28deb5e68a49227713b623c72b2b931028ea65f619b"}, + {file = "black-23.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6663f91b6feca5d06f2ccd49a10f254f9298cc1f7f49c46e498a0771b507104"}, + {file = "black-23.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9afd3f493666a0cd8f8df9a0200c6359ac53940cbde049dcb1a7eb6ee2dd7074"}, + {file = "black-23.1.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:bfffba28dc52a58f04492181392ee380e95262af14ee01d4bc7bb1b1c6ca8d27"}, + {file = "black-23.1.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c1c476bc7b7d021321e7d93dc2cbd78ce103b84d5a4cf97ed535fbc0d6660648"}, + {file = "black-23.1.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:382998821f58e5c8238d3166c492139573325287820963d2f7de4d518bd76958"}, + {file = "black-23.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bf649fda611c8550ca9d7592b69f0637218c2369b7744694c5e4902873b2f3a"}, + {file = "black-23.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:121ca7f10b4a01fd99951234abdbd97728e1240be89fde18480ffac16503d481"}, + {file = "black-23.1.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:a8471939da5e824b891b25751955be52ee7f8a30a916d570a5ba8e0f2eb2ecad"}, + {file = "black-23.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8178318cb74f98bc571eef19068f6ab5613b3e59d4f47771582f04e175570ed8"}, + {file = "black-23.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a436e7881d33acaf2536c46a454bb964a50eff59b21b51c6ccf5a40601fbef24"}, + {file = "black-23.1.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:a59db0a2094d2259c554676403fa2fac3473ccf1354c1c63eccf7ae65aac8ab6"}, + {file = "black-23.1.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:0052dba51dec07ed029ed61b18183942043e00008ec65d5028814afaab9a22fd"}, + {file = "black-23.1.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:49f7b39e30f326a34b5c9a4213213a6b221d7ae9d58ec70df1c4a307cf2a1580"}, + {file = "black-23.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:162e37d49e93bd6eb6f1afc3e17a3d23a823042530c37c3c42eeeaf026f38468"}, + {file = "black-23.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b70eb40a78dfac24842458476135f9b99ab952dd3f2dab738c1881a9b38b753"}, + {file = "black-23.1.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:a29650759a6a0944e7cca036674655c2f0f63806ddecc45ed40b7b8aa314b651"}, + {file = "black-23.1.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:bb460c8561c8c1bec7824ecbc3ce085eb50005883a6203dcfb0122e95797ee06"}, + {file = "black-23.1.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c91dfc2c2a4e50df0026f88d2215e166616e0c80e86004d0003ece0488db2739"}, + {file = "black-23.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a951cc83ab535d248c89f300eccbd625e80ab880fbcfb5ac8afb5f01a258ac9"}, + {file = "black-23.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0680d4380db3719ebcfb2613f34e86c8e6d15ffeabcf8ec59355c5e7b85bb555"}, + {file = "black-23.1.0-py3-none-any.whl", hash = "sha256:7a0f701d314cfa0896b9001df70a530eb2472babb76086344e688829efd97d32"}, + {file = "black-23.1.0.tar.gz", hash = "sha256:b0bd97bea8903f5a2ba7219257a44e3f1f9d00073d6cc1add68f0beec69692ac"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "cfgv" +version = "3.3.1" +description = "Validate configuration and produce human readable error messages." +category = "dev" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] + +[[package]] +name = "click" +version = "8.1.3" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +category = "main" +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 = "coverage" +version = "7.2.0" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "coverage-7.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90e7a4cbbb7b1916937d380beb1315b12957b8e895d7d9fb032e2038ac367525"}, + {file = "coverage-7.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:34d7211be69b215ad92298a962b2cd5a4ef4b17c7871d85e15d3d1b6dc8d8c96"}, + {file = "coverage-7.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971b49dbf713044c3e5f6451b39f65615d4d1c1d9a19948fa0f41b0245a98765"}, + {file = "coverage-7.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0557289260125a6c453ad5673ba79e5b6841d9a20c9e101f758bfbedf928a77"}, + {file = "coverage-7.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:049806ae2df69468c130f04f0fab4212c46b34ba5590296281423bb1ae379df2"}, + {file = "coverage-7.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:875b03d92ac939fbfa8ae74a35b2c468fc4f070f613d5b1692f9980099a3a210"}, + {file = "coverage-7.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c160e34e388277f10c50dc2c7b5e78abe6d07357d9fe7fcb2f3c156713fd647e"}, + {file = "coverage-7.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:32e6a730fd18b2556716039ab93278ccebbefa1af81e6aa0c8dba888cf659e6e"}, + {file = "coverage-7.2.0-cp310-cp310-win32.whl", hash = "sha256:f3ff4205aff999164834792a3949f82435bc7c7655c849226d5836c3242d7451"}, + {file = "coverage-7.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:93db11da6e728587e943dff8ae1b739002311f035831b6ecdb15e308224a4247"}, + {file = "coverage-7.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cd38140b56538855d3d5722c6d1b752b35237e7ea3f360047ce57f3fade82d98"}, + {file = "coverage-7.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9dbb21561b0e04acabe62d2c274f02df0d715e8769485353ddf3cf84727e31ce"}, + {file = "coverage-7.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:171dd3aa71a49274a7e4fc26f5bc167bfae5a4421a668bc074e21a0522a0af4b"}, + {file = "coverage-7.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4655ecd813f4ba44857af3e9cffd133ab409774e9d2a7d8fdaf4fdfd2941b789"}, + {file = "coverage-7.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1856a8c4aa77eb7ca0d42c996d0ca395ecafae658c1432b9da4528c429f2575c"}, + {file = "coverage-7.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd67df6b48db18c10790635060858e2ea4109601e84a1e9bfdd92e898dc7dc79"}, + {file = "coverage-7.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2d7daf3da9c7e0ed742b3e6b4de6cc464552e787b8a6449d16517b31bbdaddf5"}, + {file = "coverage-7.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf9e02bc3dee792b9d145af30db8686f328e781bd212fdef499db5e9e4dd8377"}, + {file = "coverage-7.2.0-cp311-cp311-win32.whl", hash = "sha256:3713a8ec18781fda408f0e853bf8c85963e2d3327c99a82a22e5c91baffcb934"}, + {file = "coverage-7.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:88ae5929f0ef668b582fd7cad09b5e7277f50f912183cf969b36e82a1c26e49a"}, + {file = "coverage-7.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5e29a64e9586194ea271048bc80c83cdd4587830110d1e07b109e6ff435e5dbc"}, + {file = "coverage-7.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d5302eb84c61e758c9d68b8a2f93a398b272073a046d07da83d77b0edc8d76b"}, + {file = "coverage-7.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c9fffbc39dc4a6277e1525cab06c161d11ee3995bbc97543dc74fcec33e045b"}, + {file = "coverage-7.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6ceeab5fca62bca072eba6865a12d881f281c74231d2990f8a398226e1a5d96"}, + {file = "coverage-7.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:28563a35ef4a82b5bc5160a01853ce62b9fceee00760e583ffc8acf9e3413753"}, + {file = "coverage-7.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bfa065307667f1c6e1f4c3e13f415b0925e34e56441f5fda2c84110a4a1d8bda"}, + {file = "coverage-7.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7f992b32286c86c38f07a8b5c3fc88384199e82434040a729ec06b067ee0d52c"}, + {file = "coverage-7.2.0-cp37-cp37m-win32.whl", hash = "sha256:2c15bd09fd5009f3a79c8b3682b52973df29761030b692043f9834fc780947c4"}, + {file = "coverage-7.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f332d61fbff353e2ef0f3130a166f499c3fad3a196e7f7ae72076d41a6bfb259"}, + {file = "coverage-7.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:577a8bc40c01ad88bb9ab1b3a1814f2f860ff5c5099827da2a3cafc5522dadea"}, + {file = "coverage-7.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9240a0335365c29c968131bdf624bb25a8a653a9c0d8c5dbfcabf80b59c1973c"}, + {file = "coverage-7.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:358d3bce1468f298b19a3e35183bdb13c06cdda029643537a0cc37e55e74e8f1"}, + {file = "coverage-7.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:932048364ff9c39030c6ba360c31bf4500036d4e15c02a2afc5a76e7623140d4"}, + {file = "coverage-7.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7efa21611ffc91156e6f053997285c6fe88cfef3fb7533692d0692d2cb30c846"}, + {file = "coverage-7.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:465ea431c3b78a87e32d7d9ea6d081a1003c43a442982375cf2c247a19971961"}, + {file = "coverage-7.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0f03c229f1453b936916f68a47b3dfb5e84e7ad48e160488168a5e35115320c8"}, + {file = "coverage-7.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:40785553d68c61e61100262b73f665024fd2bb3c6f0f8e2cd5b13e10e4df027b"}, + {file = "coverage-7.2.0-cp38-cp38-win32.whl", hash = "sha256:b09dd7bef59448c66e6b490cc3f3c25c14bc85d4e3c193b81a6204be8dd355de"}, + {file = "coverage-7.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:dc4f9a89c82faf6254d646180b2e3aa4daf5ff75bdb2c296b9f6a6cf547e26a7"}, + {file = "coverage-7.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c243b25051440386179591a8d5a5caff4484f92c980fb6e061b9559da7cc3f64"}, + {file = "coverage-7.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b8fd32f85b256fc096deeb4872aeb8137474da0c0351236f93cbedc359353d6"}, + {file = "coverage-7.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7f2a7df523791e6a63b40360afa6792a11869651307031160dc10802df9a252"}, + {file = "coverage-7.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da32526326e8da0effb452dc32a21ffad282c485a85a02aeff2393156f69c1c3"}, + {file = "coverage-7.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1153a6156715db9d6ae8283480ae67fb67452aa693a56d7dae9ffe8f7a80da"}, + {file = "coverage-7.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:74cd60fa00f46f28bd40048d6ca26bd58e9bee61d2b0eb4ec18cea13493c003f"}, + {file = "coverage-7.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:59a427f8a005aa7254074719441acb25ac2c2f60c1f1026d43f846d4254c1c2f"}, + {file = "coverage-7.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c3c4beddee01c8125a75cde3b71be273995e2e9ec08fbc260dd206b46bb99969"}, + {file = "coverage-7.2.0-cp39-cp39-win32.whl", hash = "sha256:08e3dd256b8d3e07bb230896c8c96ec6c5dffbe5a133ba21f8be82b275b900e8"}, + {file = "coverage-7.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad12c74c6ce53a027f5a5ecbac9be20758a41c85425c1bbab7078441794b04ee"}, + {file = "coverage-7.2.0-pp37.pp38.pp39-none-any.whl", hash = "sha256:ffa637a2d5883298449a5434b699b22ef98dd8e2ef8a1d9e60fa9cfe79813411"}, + {file = "coverage-7.2.0.tar.gz", hash = "sha256:9cc9c41aa5af16d845b53287051340c363dd03b7ef408e45eec3af52be77810d"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "dill" +version = "0.3.6" +description = "serialize all of python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"}, + {file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] + +[[package]] +name = "distlib" +version = "0.3.6" +description = "Distribution utilities" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, + {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.0" +description = "Backport of PEP 654 (exception groups)" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, + {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "filelock" +version = "3.9.0" +description = "A platform independent file lock." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "filelock-3.9.0-py3-none-any.whl", hash = "sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d"}, + {file = "filelock-3.9.0.tar.gz", hash = "sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de"}, +] + +[package.extras] +docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] +testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "flake8" +version = "6.0.0" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"}, + {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.10.0,<2.11.0" +pyflakes = ">=3.0.0,<3.1.0" + +[[package]] +name = "flask" +version = "2.2.3" +description = "A simple framework for building complex web applications." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Flask-2.2.3-py3-none-any.whl", hash = "sha256:c0bec9477df1cb867e5a67c9e1ab758de9cb4a3e52dd70681f59fa40a62b3f2d"}, + {file = "Flask-2.2.3.tar.gz", hash = "sha256:7eb373984bf1c770023fce9db164ed0c3353cd0b53f130f4693da0ca756a2e6d"}, +] + +[package.dependencies] +click = ">=8.0" +itsdangerous = ">=2.0" +Jinja2 = ">=3.0" +Werkzeug = ">=2.2.2" + +[package.extras] +async = ["asgiref (>=3.2)"] +dotenv = ["python-dotenv"] + +[[package]] +name = "identify" +version = "2.5.18" +description = "File identification library for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "identify-2.5.18-py2.py3-none-any.whl", hash = "sha256:93aac7ecf2f6abf879b8f29a8002d3c6de7086b8c28d88e1ad15045a15ab63f9"}, + {file = "identify-2.5.18.tar.gz", hash = "sha256:89e144fa560cc4cffb6ef2ab5e9fb18ed9f9b3cb054384bab4b95c12f6c309fe"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "isort" +version = "5.12.0" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, +] + +[package.extras] +colors = ["colorama (>=0.4.3)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "itsdangerous" +version = "2.1.2" +description = "Safely pass data to untrusted environments and back." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, + {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, +] + +[[package]] +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "lazy-object-proxy" +version = "1.9.0" +description = "A fast and thorough lazy object proxy." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, +] + +[[package]] +name = "markupsafe" +version = "2.1.2" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, + {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +category = "dev" +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." +category = "dev" +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 = "nodeenv" +version = "1.7.0" +description = "Node.js virtual environment builder" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, + {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, +] + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "packaging" +version = "23.0" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, + {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, +] + +[[package]] +name = "pathspec" +version = "0.11.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"}, + {file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"}, +] + +[[package]] +name = "platformdirs" +version = "3.0.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.0.0-py3-none-any.whl", hash = "sha256:b1d5eb14f221506f50d6604a561f4c5786d9e80355219694a1b244bcd96f4567"}, + {file = "platformdirs-3.0.0.tar.gz", hash = "sha256:8a1228abb1ef82d788f74139988b137e78692984ec7b08eaa6c65f1723af28f9"}, +] + +[package.extras] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "3.1.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.1.0-py2.py3-none-any.whl", hash = "sha256:7001dfcd174540658822b1fd3630ceadf4f41375a5d1844b5c3b3830f227348c"}, + {file = "pre_commit-3.1.0.tar.gz", hash = "sha256:61bd9f1b96d3d1e763f2a9a0f8522aed341646800642ff6803c73fac5781f5b7"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "pycodestyle" +version = "2.10.0" +description = "Python style guide checker" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, + {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, +] + +[[package]] +name = "pyflakes" +version = "3.0.1" +description = "passive checker of Python programs" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"}, + {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, +] + +[[package]] +name = "pylint" +version = "2.16.2" +description = "python code static checker" +category = "dev" +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "pylint-2.16.2-py3-none-any.whl", hash = "sha256:ff22dde9c2128cd257c145cfd51adeff0be7df4d80d669055f24a962b351bbe4"}, + {file = "pylint-2.16.2.tar.gz", hash = "sha256:13b2c805a404a9bf57d002cd5f054ca4d40b0b87542bdaba5e05321ae8262c84"}, +] + +[package.dependencies] +astroid = ">=2.14.2,<=2.16.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = [ + {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, +] +isort = ">=4.2.5,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.10.1" + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pylint-per-file-ignores" +version = "1.2.0" +description = "A pylint plugin to ignore error codes per file." +category = "dev" +optional = false +python-versions = ">=3.8.1,<4.0.0" +files = [ + {file = "pylint_per_file_ignores-1.2.0-py3-none-any.whl", hash = "sha256:15839fcac882367c088625215a141e60a8ab11e6abe38e66ad2167c507403fc3"}, + {file = "pylint_per_file_ignores-1.2.0.tar.gz", hash = "sha256:665e29dd02061bbdd70ced7273a6971880fe97a3a2c15615ad2b31e567559b3c"}, +] + +[package.dependencies] +tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "pytest" +version = "7.2.1" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, + {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, +] + +[package.dependencies] +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "4.0.0" +description = "Pytest plugin for measuring coverage." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] + +[[package]] +name = "setuptools" +version = "67.4.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-67.4.0-py3-none-any.whl", hash = "sha256:f106dee1b506dee5102cc3f3e9e68137bbad6d47b616be7991714b0c62204251"}, + {file = "setuptools-67.4.0.tar.gz", hash = "sha256:e5fd0a713141a4a105412233c63dc4e17ba0090c8e8334594ac790ec97792330"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tomlkit" +version = "0.11.6" +description = "Style preserving TOML library" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"}, + {file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"}, +] + +[[package]] +name = "typing-extensions" +version = "4.5.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, + {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, +] + +[[package]] +name = "virtualenv" +version = "20.19.0" +description = "Virtual Python Environment builder" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.19.0-py3-none-any.whl", hash = "sha256:54eb59e7352b573aa04d53f80fc9736ed0ad5143af445a1e539aada6eb947dd1"}, + {file = "virtualenv-20.19.0.tar.gz", hash = "sha256:37a640ba82ed40b226599c522d411e4be5edb339a0c0de030c0dc7b646d61590"}, +] + +[package.dependencies] +distlib = ">=0.3.6,<1" +filelock = ">=3.4.1,<4" +platformdirs = ">=2.4,<4" + +[package.extras] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23)", "pytest (>=7.2.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "werkzeug" +version = "2.2.3" +description = "The comprehensive WSGI web application library." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Werkzeug-2.2.3-py3-none-any.whl", hash = "sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612"}, + {file = "Werkzeug-2.2.3.tar.gz", hash = "sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe"}, +] + +[package.dependencies] +MarkupSafe = ">=2.1.1" + +[package.extras] +watchdog = ["watchdog"] + +[[package]] +name = "wrapt" +version = "1.14.1" +description = "Module for decorators, wrappers and monkey patching." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, + {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, + {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, + {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, + {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, + {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, + {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, + {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, + {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, + {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, + {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, + {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, + {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, + {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, + {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, + {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "56c2f01c842d55c576e49583506eceebf3962a1469f1925282dcb0391d3ce7c2" diff --git a/pyproject.toml b/pyproject.toml index ac68c2a..dbde270 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,7 @@ pre-commit = "^3.0.4" pylint = "^2.16.2" pylint-per-file-ignores = "^1.2.0" pytest = "^7.2.1" +pytest-cov = "^4.0.0" [build-system] requires = ["poetry-core"] diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_fake.py b/tests/test_fake.py new file mode 100644 index 0000000..4467546 --- /dev/null +++ b/tests/test_fake.py @@ -0,0 +1,2 @@ +def test_answer(): + assert True \ No newline at end of file From 6890ea1e9a92d2f27ddf8d92c6b2cbe0b8c1c265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 17:01:07 +0100 Subject: [PATCH 05/26] ci: update to ubuntu github hosted --- .github/workflows/pytest.yml | 2 +- .github/workflows/python-publish.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 3fd8cfa..f4e8777 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -15,7 +15,7 @@ jobs: matrix: python-version: ["3.8", "3.9", "3.10", "3.11"] - runs-on: self-hosted + runs-on: ubuntu-22.04 container: python:{{ matrix.python-version }}-alpine steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 06909ea..1a51975 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -17,7 +17,7 @@ permissions: jobs: deploy: - runs-on: self-hosted + runs-on: ubuntu-22.04 container: python:3.11-alpine steps: - uses: actions/checkout@v3 From e354fc165dda841e663f70b5e690c20525460b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 17:10:04 +0100 Subject: [PATCH 06/26] chore: add convential commit hook --- .pre-commit-config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1870af9..40618ed 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,6 +15,11 @@ repos: - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files + - repo: https://github.com/compilerla/conventional-pre-commit + rev: v2.1.1 + hooks: + - id: conventional-pre-commit + stages: [commit-msg] - repo: https://github.com/psf/black rev: 23.1.0 hooks: From dc6fd5cfef2caf400321c6075c452dd59b61498b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 17:21:32 +0100 Subject: [PATCH 07/26] fix(ci): missing dollar --- .github/workflows/pytest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index f4e8777..a19864b 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -16,7 +16,7 @@ jobs: python-version: ["3.8", "3.9", "3.10", "3.11"] runs-on: ubuntu-22.04 - container: python:{{ matrix.python-version }}-alpine + container: python:${{ matrix.python-version }}-alpine steps: - uses: actions/checkout@v3 From 8f60a8ff2afa820c15f5c1693b4086d0b1e47f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 17:24:39 +0100 Subject: [PATCH 08/26] fix(pre-commit): invalid values in hooks --- .pre-commit-config.yaml | 6 +++--- tests/test_fake.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 40618ed..01878f5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,6 +20,7 @@ repos: hooks: - id: conventional-pre-commit stages: [commit-msg] + args: [] - repo: https://github.com/psf/black rev: 23.1.0 hooks: @@ -37,13 +38,12 @@ repos: entry: pylint language: system types: [python] - # TODO: change this on GitHub - args: [-rn, -sn, --rcfile=python/pyproject.toml] + args: [-rn, -sn, --rcfile=pyproject.toml] - repo: https://github.com/pycqa/flake8 rev: 6.0.0 hooks: - id: flake8 - args: [--config=python/.flake8] + args: [--config=.flake8] - repo: https://github.com/pycqa/pydocstyle rev: 6.3.0 hooks: diff --git a/tests/test_fake.py b/tests/test_fake.py index 4467546..fa77e7b 100644 --- a/tests/test_fake.py +++ b/tests/test_fake.py @@ -1,2 +1,2 @@ def test_answer(): - assert True \ No newline at end of file + assert True From e3f7920e9cb3d685ca11d8059d40e17e3e68ade9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 17:48:49 +0100 Subject: [PATCH 09/26] fix(ci): missing python version cache key for deps --- .github/actions/setup-poetry/action.yml | 19 ++++++++++++++----- .github/workflows/pytest.yml | 5 ++++- .github/workflows/python-publish.yml | 1 + 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/actions/setup-poetry/action.yml b/.github/actions/setup-poetry/action.yml index fa96460..1fe1bd0 100644 --- a/.github/actions/setup-poetry/action.yml +++ b/.github/actions/setup-poetry/action.yml @@ -2,9 +2,11 @@ name: Set up poetry description: Install poetry and python dependencies inputs: groups: - description: "Poetry groups." - required: false - default: "dev" + description: "Poetry dependencies groups." + required: true + python-version: + description: "Python version." + required: true runs: using: "composite" steps: @@ -14,18 +16,25 @@ runs: apk update apk add --no-cache bash curl + - name: Load cached Poetry installation + id: cached-poetry + uses: actions/cache@v3 + with: + path: ~/.local + key: poetry-${{ github.event.inputs.python-version }}-v0 + - uses: snok/install-poetry@v1 with: - version: 1.3.2 virtualenvs-create: true virtualenvs-in-project: true + if: steps.cached-poetry.outputs.cache-hit != 'true' - name: Cache poetry dependencies id: cache-poetry-deps uses: actions/cache@v3 with: path: .venv - key: pydeps-${{ hashFiles('**/poetry.lock') }}-${{ github.event.inputs.groups }} + key: venv-${{ github.event.inputs.python-version }}-${{ hashFiles('**/poetry.lock') }}-${{ github.event.inputs.groups }} - name: Install poetry dependencies shell: bash diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index a19864b..85d0f37 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -21,10 +21,13 @@ jobs: - uses: actions/checkout@v3 - uses: ./.github/actions/setup-poetry + with: + groups: "dev" + python-version: ${{ matrix.python-version }} - name: Test with pytest working-directory: tests - run: poetry run pytest tests --junitxml=junit/test-results-${{ matrix.python-version }}.xml + run: poetry run pytest --junitxml=junit/test-results-${{ matrix.python-version }}.xml - name: Upload pytest test results uses: actions/upload-artifact@v3 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 1a51975..3ed75c8 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -25,6 +25,7 @@ jobs: - uses: ./.github/actions/setup-poetry with: groups: "" + python-version: "3.11" - name: Publish package run: poetry publish --build From 3063cc7acf99e4792507d70d5e8aeb94407568a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 17:57:07 +0100 Subject: [PATCH 10/26] fix: minimum python version in pyproject --- .github/actions/setup-poetry/action.yml | 6 +++--- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/actions/setup-poetry/action.yml b/.github/actions/setup-poetry/action.yml index 1fe1bd0..700e62b 100644 --- a/.github/actions/setup-poetry/action.yml +++ b/.github/actions/setup-poetry/action.yml @@ -21,7 +21,7 @@ runs: uses: actions/cache@v3 with: path: ~/.local - key: poetry-${{ github.event.inputs.python-version }}-v0 + key: poetry-${{ inputs.python-version }}-v0 - uses: snok/install-poetry@v1 with: @@ -34,9 +34,9 @@ runs: uses: actions/cache@v3 with: path: .venv - key: venv-${{ github.event.inputs.python-version }}-${{ hashFiles('**/poetry.lock') }}-${{ github.event.inputs.groups }} + key: venv-${{ inputs.python-version }}-${{ hashFiles('**/poetry.lock') }}-${{ inputs.groups }} - name: Install poetry dependencies shell: bash - run: poetry install --no-interaction --no-root --with=${{ github.event.inputs.groups }} + run: poetry install --no-interaction --no-root --with=${{ inputs.groups }} if: steps.cache-deps.outputs.cache-hit != 'true' diff --git a/pyproject.toml b/pyproject.toml index dbde270..f82681d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ packages = [ include = ["CHANGELOG.md"] [tool.poetry.dependencies] -python = "^3.10" +python = ">=3.8, <3.12" flask = "^2.2.2" typing-extensions = { version = "^4.4.0", python = "<3.11" } From 71adc8cbd23bf45355c476a5b5674f604c38c520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 17:58:51 +0100 Subject: [PATCH 11/26] chore: poetry lock --- poetry.lock | 43 +++++++++++++++++++++++++++++++++++++++++-- pyproject.toml | 2 +- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index a3d5993..88d7a7c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -97,6 +97,7 @@ packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -299,6 +300,7 @@ files = [ [package.dependencies] click = ">=8.0" +importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""} itsdangerous = ">=2.0" Jinja2 = ">=3.0" Werkzeug = ">=2.2.2" @@ -322,6 +324,26 @@ files = [ [package.extras] license = ["ukkonen"] +[[package]] +name = "importlib-metadata" +version = "6.0.0" +description = "Read metadata from Python packages" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, + {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -650,6 +672,7 @@ mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomlkit = ">=0.10.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [package.extras] spelling = ["pyenchant (>=3.2,<4.0)"] @@ -929,7 +952,23 @@ files = [ {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, ] +[[package]] +name = "zipp" +version = "3.14.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "zipp-3.14.0-py3-none-any.whl", hash = "sha256:188834565033387710d046e3fe96acfc9b5e86cbca7f39ff69cf21a4128198b7"}, + {file = "zipp-3.14.0.tar.gz", hash = "sha256:9e5421e176ef5ab4c0ad896624e87a7b2f07aca746c9b2aa305952800cb8eecb"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + [metadata] lock-version = "2.0" -python-versions = "^3.10" -content-hash = "56c2f01c842d55c576e49583506eceebf3962a1469f1925282dcb0391d3ce7c2" +python-versions = ">=3.8.1, <3.12" +content-hash = "406b7945bc488fbded9dabdcddae2825c22d16dda95f479732625b110044c921" diff --git a/pyproject.toml b/pyproject.toml index f82681d..5cda995 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ packages = [ include = ["CHANGELOG.md"] [tool.poetry.dependencies] -python = ">=3.8, <3.12" +python = ">=3.8.1, <3.12" flask = "^2.2.2" typing-extensions = { version = "^4.4.0", python = "<3.11" } From 2e4141e90c6513cdd833d8f9cae50bc72e2fbe7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 18:06:44 +0100 Subject: [PATCH 12/26] chore(ci): do not install dev dependencies --- .github/actions/setup-poetry/action.yml | 2 +- .github/workflows/pytest.yml | 2 +- poetry.lock | 2 +- pyproject.toml | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/actions/setup-poetry/action.yml b/.github/actions/setup-poetry/action.yml index 700e62b..6e2b732 100644 --- a/.github/actions/setup-poetry/action.yml +++ b/.github/actions/setup-poetry/action.yml @@ -38,5 +38,5 @@ runs: - name: Install poetry dependencies shell: bash - run: poetry install --no-interaction --no-root --with=${{ inputs.groups }} + run: poetry install --no-interaction --no-root --only main,${{ inputs.groups }} if: steps.cache-deps.outputs.cache-hit != 'true' diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 85d0f37..de32ad3 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -22,7 +22,7 @@ jobs: - uses: ./.github/actions/setup-poetry with: - groups: "dev" + groups: "test" python-version: ${{ matrix.python-version }} - name: Test with pytest diff --git a/poetry.lock b/poetry.lock index 88d7a7c..c2bf9fc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -971,4 +971,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "2.0" python-versions = ">=3.8.1, <3.12" -content-hash = "406b7945bc488fbded9dabdcddae2825c22d16dda95f479732625b110044c921" +content-hash = "f2b00cd47fc8070e43effac91c89e1e031a6b66a6684c75739e6f6bbed1b177b" diff --git a/pyproject.toml b/pyproject.toml index 5cda995..8aad838 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,10 @@ python = ">=3.8.1, <3.12" flask = "^2.2.2" typing-extensions = { version = "^4.4.0", python = "<3.11" } +[tool.poetry.group.test.dependencies] +pytest = "^7.2.1" +pytest-cov = "^4.0.0" + [tool.poetry.group.dev.dependencies] autoflake = "^1.7.7" black = "^23.01.0" @@ -46,8 +50,6 @@ isort = "^5.10.1" pre-commit = "^3.0.4" pylint = "^2.16.2" pylint-per-file-ignores = "^1.2.0" -pytest = "^7.2.1" -pytest-cov = "^4.0.0" [build-system] requires = ["poetry-core"] From b1ac6e4c6c3a204c290ef3e96349865e80e845d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 18:13:25 +0100 Subject: [PATCH 13/26] test(ci): remove python 3.8 --- .github/workflows/pytest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index de32ad3..1259c8a 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -13,7 +13,7 @@ jobs: test: strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11"] runs-on: ubuntu-22.04 container: python:${{ matrix.python-version }}-alpine From 6dc6da1df774b3e41bfbfe94e29e575821040d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 18:40:57 +0100 Subject: [PATCH 14/26] test(ci): remove alpine containers --- .github/actions/setup-poetry/action.yml | 11 +++-------- .github/workflows/pytest.yml | 6 +++--- .github/workflows/python-publish.yml | 6 +++--- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/.github/actions/setup-poetry/action.yml b/.github/actions/setup-poetry/action.yml index 6e2b732..978a445 100644 --- a/.github/actions/setup-poetry/action.yml +++ b/.github/actions/setup-poetry/action.yml @@ -10,20 +10,15 @@ inputs: runs: using: "composite" steps: - - name: Install bash and curl - shell: sh - run: | - apk update - apk add --no-cache bash curl - - name: Load cached Poetry installation id: cached-poetry uses: actions/cache@v3 with: path: ~/.local - key: poetry-${{ inputs.python-version }}-v0 + key: poetry-${{ inputs.python-version }}-v1 - - uses: snok/install-poetry@v1 + - name: Install Poetry + uses: snok/install-poetry@v1 with: virtualenvs-create: true virtualenvs-in-project: true diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 1259c8a..4ab8faf 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -13,14 +13,14 @@ jobs: test: strategy: matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] runs-on: ubuntu-22.04 - container: python:${{ matrix.python-version }}-alpine steps: - uses: actions/checkout@v3 - - uses: ./.github/actions/setup-poetry + - name: Setup Poetry + uses: ./.github/actions/setup-poetry with: groups: "test" python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 3ed75c8..652c156 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -18,13 +18,13 @@ permissions: jobs: deploy: runs-on: ubuntu-22.04 - container: python:3.11-alpine steps: - uses: actions/checkout@v3 - - uses: ./.github/actions/setup-poetry + - name: Setup Poetry + uses: ./.github/actions/setup-poetry with: - groups: "" + groups: "" # will only install the main group python-version: "3.11" - name: Publish package From a9e49b042e758c1c4353c781ac66d00fd635d338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 18:57:04 +0100 Subject: [PATCH 15/26] test(ci): experiment with junit report --- .github/actions/setup-poetry/action.yml | 4 ++-- .github/dependabot.yml | 13 +++++++------ .github/workflows/pytest.yml | 17 ++++++++++------- .github/workflows/python-publish.yml | 5 +++-- .github/workflows/report.yml | 25 +++++++++++++++++++++++++ 5 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/report.yml diff --git a/.github/actions/setup-poetry/action.yml b/.github/actions/setup-poetry/action.yml index 978a445..fb5ce27 100644 --- a/.github/actions/setup-poetry/action.yml +++ b/.github/actions/setup-poetry/action.yml @@ -24,14 +24,14 @@ runs: virtualenvs-in-project: true if: steps.cached-poetry.outputs.cache-hit != 'true' - - name: Cache poetry dependencies + - name: Cache Poetry dependencies id: cache-poetry-deps uses: actions/cache@v3 with: path: .venv key: venv-${{ inputs.python-version }}-${{ hashFiles('**/poetry.lock') }}-${{ inputs.groups }} - - name: Install poetry dependencies + - name: Install Poetry dependencies shell: bash run: poetry install --no-interaction --no-root --only main,${{ inputs.groups }} if: steps.cache-deps.outputs.cache-hit != 'true' diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8b00cbb..f669372 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,12 +1,13 @@ +--- version: 2 updates: - - package-ecosystem: "github-actions" + - package-ecosystem: github-actions # Workflow files stored in the # default location of `.github/workflows` - directory: "/" + directory: / schedule: - interval: "weekly" - - package-ecosystem: "pip" - directory: "/" + interval: weekly + - package-ecosystem: pip + directory: / schedule: - interval: "weekly" + interval: weekly diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 4ab8faf..c36340e 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -1,10 +1,11 @@ +--- name: Pytest on: push: - branches: ["main"] + branches: [main] pull_request: - branches: ["main"] + branches: [main] permissions: contents: read @@ -13,7 +14,7 @@ jobs: test: strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ['3.8', '3.9', '3.10', '3.11'] runs-on: ubuntu-22.04 steps: @@ -22,17 +23,19 @@ jobs: - name: Setup Poetry uses: ./.github/actions/setup-poetry with: - groups: "test" + groups: test python-version: ${{ matrix.python-version }} - name: Test with pytest working-directory: tests - run: poetry run pytest --junitxml=junit/test-results-${{ matrix.python-version }}.xml + run: poetry run pytest --junitxml=junit/test-results-${{ matrix.python-version + }}.xml - - name: Upload pytest test results + - name: Upload pytest Report uses: actions/upload-artifact@v3 with: name: pytest-results-${{ matrix.python-version }} - path: junit/test-results-${{ matrix.python-version }}.xml + path: tests/junit/test-results-${{ matrix.python-version }}.xml + retention-days: 3 # Use always() to always run this step to publish test results when there are test failures if: ${{ always() }} diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 652c156..c5f5ed6 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,3 +1,4 @@ +--- # This workflow will upload a Python Package using Twine when a release is created # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries @@ -24,8 +25,8 @@ jobs: - name: Setup Poetry uses: ./.github/actions/setup-poetry with: - groups: "" # will only install the main group - python-version: "3.11" + groups: '' # will only install the main group + python-version: '3.11' - name: Publish package run: poetry publish --build diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml new file mode 100644 index 0000000..b710333 --- /dev/null +++ b/.github/workflows/report.yml @@ -0,0 +1,25 @@ +--- +name: report +on: + workflow_run: + workflows: [test] + types: [completed] + +permissions: + checks: write + +jobs: + checks: + runs-on: ubuntu-22.04 + steps: + - name: Download Test Report + uses: dawidd6/action-download-artifact@v2 + with: + name: junit-test-results + workflow: ${{ github.event.workflow.id }} + run_id: ${{ github.event.workflow_run.id }} + - name: Publish Test Report + uses: mikepenz/action-junit-report@v3 + with: + commit: ${{github.event.workflow_run.head_sha}} + report_paths: tests/junit/test-results-*.xml From 3d3c25edcb68065c1e629d6c5a2799ff92850f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Fri, 24 Feb 2023 18:59:03 +0100 Subject: [PATCH 16/26] fix(ci): fix bad names --- .github/workflows/pytest.yml | 2 +- .github/workflows/python-publish.yml | 6 +++--- .github/workflows/report.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index c36340e..a497247 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -1,5 +1,5 @@ --- -name: Pytest +name: pytest on: push: diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index c5f5ed6..1033dcc 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -7,7 +7,7 @@ # separate terms of service, privacy policy, and support # documentation. -name: Upload Python Package +name: python-publish on: release: @@ -25,8 +25,8 @@ jobs: - name: Setup Poetry uses: ./.github/actions/setup-poetry with: - groups: '' # will only install the main group - python-version: '3.11' + groups: "" # will only install the main group + python-version: "3.11" - name: Publish package run: poetry publish --build diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml index b710333..6b58dce 100644 --- a/.github/workflows/report.yml +++ b/.github/workflows/report.yml @@ -2,7 +2,7 @@ name: report on: workflow_run: - workflows: [test] + workflows: [pytest] types: [completed] permissions: From 195db24ec22adbd99acbfda7d180fd5a84e54c6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Mon, 27 Feb 2023 12:07:57 +0100 Subject: [PATCH 17/26] fix(ci): missing install python --- .github/workflows/pytest.yml | 20 ++++++++++++++++---- .github/workflows/python-publish.yml | 8 +++++++- .github/workflows/report.yml | 1 + 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index a497247..158816e 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -14,24 +14,36 @@ jobs: test: strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ["3.8", "3.9", "3.10", "3.11"] runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 - - name: Setup Poetry + - name: Set up python ${{ matrix.python-version }} + id: setup-python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Set up Poetry uses: ./.github/actions/setup-poetry with: groups: test python-version: ${{ matrix.python-version }} + - name: Print versions + run: | + python --version + poetry --version + - name: Test with pytest working-directory: tests - run: poetry run pytest --junitxml=junit/test-results-${{ matrix.python-version + run: + poetry run pytest --junitxml=junit/test-results-${{ matrix.python-version }}.xml - - name: Upload pytest Report + - name: Upload pytest report uses: actions/upload-artifact@v3 with: name: pytest-results-${{ matrix.python-version }} diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 1033dcc..e45d2b8 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -22,7 +22,13 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Setup Poetry + - name: Set up python 3.11 + id: setup-python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: Set up Poetry uses: ./.github/actions/setup-poetry with: groups: "" # will only install the main group diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml index 6b58dce..359cf3d 100644 --- a/.github/workflows/report.yml +++ b/.github/workflows/report.yml @@ -1,5 +1,6 @@ --- name: report + on: workflow_run: workflows: [pytest] From 4c1d0e7b1210412e9ed9d3d65b430f383450e610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Mon, 27 Feb 2023 14:50:25 +0100 Subject: [PATCH 18/26] chore: update README --- .github/workflows/report.yml | 1 + README.md | 93 ++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 53 deletions(-) diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml index 359cf3d..4cf33b7 100644 --- a/.github/workflows/report.yml +++ b/.github/workflows/report.yml @@ -19,6 +19,7 @@ jobs: name: junit-test-results workflow: ${{ github.event.workflow.id }} run_id: ${{ github.event.workflow_run.id }} + - name: Publish Test Report uses: mikepenz/action-junit-report@v3 with: diff --git a/README.md b/README.md index 0a9d474..7060d2a 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,55 @@ -# Serverless Functions Python 💜 +# Scaleway Functions Python 💜 -Scaleway Serverless Functions is a framework to provide a good developer experience to write Serverless Functions. +A framework that provides tools when working with Scaleway Serverless Functions in Python. -Serverless Functions make it easy to deploy, scale, and optimize your workloads on the cloud. +## Installation -Get started with Scaleway Functions (we support multiple languages :rocket:): +You can use `pip` to install the framework: -- [Scaleway Serverless Functions Documentation](https://www.scaleway.com/en/docs/serverless/functions/quickstart/) -- [Scaleway Serverless Framework plugin](https://github.com/scaleway/serverless-scaleway-functions) -- [Scaleway Serverless Examples](https://github.com/scaleway/serverless-examples) -- [Scaleway Cloud Provider](https://scaleway.com) - -Testing frameworks for Scaleway Serverless Functions in other languages can be found here: - -- [Node](https://github.com/scaleway/serverless-functions-node) -- [Go](https://github.com/scaleway/serverless-functions-go) -- [PHP](https://github.com/scaleway/serverless-functions-php) -- [Rust](https://github.com/scaleway/serverless-functions-rust) - -## 🚀 Features - -This repository aims to provide the best experience: **local testing, utils, documentation etc...** -additionally we love to share things with the community and we want to expose receipts to the public. That's why we make our framework publicly available to help the community! - -## 🏡 Local testing - -What this package does: - -- **Format Input**: FaaS have a specific input format encapsulating the body received by functions to add some useful data. - The local testing package lets you interact with this data. -- **Advanced debugging**: To improve developer experience you can run your handler locally, on your computer to make - it simpler to debug by running your code step-by-step or reading output directly before deploying it. - -What this package does not: - -- **Build functions**: When your function is uploaded we build it in an environment that can be different than yours. Our build pipelines support - tons of different packages but sometimes it requires a specific setup, for example, if your function requires a specific 3D system library. -If you have compatibility issues, please see the help section. - -## 🛟 Help & support - -- Scaleway support is available on Scaleway Console. -- Additionally, you can join our [Slack Community](https://www.scaleway.com/en/docs/tutorials/scaleway-slack-community/) - -## 🎓 Contributing - -We welcome all contributions to our open-source projects, please see our contributing guidelines . - -Do not hesitate to raise issues and pull requests we will have a look at them. +```console +pip install scaleway-functions-python +``` ## Usage -Here's how you can get started with the framework: +### 🏡 Local testing + +When working with Serverless functions, it can be hard to test your function without deploying it. The framework provides a utility function that will run your handler locally: ```python -from serverless_functions_python import serve_handler_locally +# In handler.py -def handler(event, context): +# Define your Serverless Handler. +def handler(event, _context): + if event["method"] != "GET": + return {"statusCode": 405, "body": "Invalid method!"} return "Hello World!" if __name__ == "__main__": + # The import is conditional so that you do not need + # to package the library when deploying on Scaleway Functions. + from scaleway_functions_python import serve_handler_locally serve_handler_locally(handler, port=8080) ``` -This will expose your handler on a local web server allowing you to test your function. +```console +$ python handler.py +$ curl http://localhost:8080 +> Hello World! +$ curl -X POST http://localhost:8080 +> Invalid method! +``` + +### 🧱 Type hints + +The framework provides some types hints to make it easier to develop your handler. See this [example](examples/mirror.py) for more information on how to use them. + +Check out the examples to get started! -Some information will be added to requests for example specific headers. For local development, additional header values are hardcoded -to make it easy to differentiate them. In production, you will be able to observe headers with exploitable data. +## 🛟 Help & support -Local testing part of this framework does not aim to simulate 100% production but it aims to make it easier to work with functions locally. +- Scaleway support is available on Scaleway Console. +- Additionally, you can join our [Slack Community](https://www.scaleway.com/en/docs/tutorials/scaleway-slack-community/) ## ❓ FAQ @@ -86,3 +67,9 @@ this tool has been developed to simulate this part. **Do I need to deploy my function differently?** No. This framework does not affect deployment or performance. + +## 🎓 Contributing + +We welcome all contributions to our open-source projects, please see our contributing guidelines. + +Do not hesitate to raise issues and pull requests we will have a look at them. From c6a3333f7f0383d40526bc7b8ed44bd87cfe459a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Mon, 27 Feb 2023 15:48:20 +0100 Subject: [PATCH 19/26] chore: clean up gitignore --- .gitignore | 113 ----------------------------------------------------- 1 file changed, 113 deletions(-) diff --git a/.gitignore b/.gitignore index e277343..e325b94 100644 --- a/.gitignore +++ b/.gitignore @@ -5,28 +5,8 @@ __pycache__/ *.py[cod] *$py.class -# C extensions -*.so - # Distribution / packaging -.Python -build/ -develop-eggs/ dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST # PyInstaller # Usually these files are written by a python script from a template @@ -34,93 +14,20 @@ MANIFEST *.manifest *.spec -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - # Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ .coverage .coverage.* .cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ .pytest_cache/ cover/ -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - # Flask stuff: instance/ .webassets-cache -# Scrapy stuff: -.scrapy - # Sphinx documentation docs/_build/ -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - # Environments .env .venv @@ -130,16 +37,6 @@ ENV/ env.bak/ venv.bak/ -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - # mypy .mypy_cache/ .dmypy.json @@ -150,13 +47,3 @@ dmypy.json # pytype static type analyzer .pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ From 19a5335af3b37296e8d8113858312051eccc305c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Mon, 27 Feb 2023 17:56:04 +0100 Subject: [PATCH 20/26] docs: use README from serverless go --- README.md | 65 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 7060d2a..531bf1c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,24 @@ -# Scaleway Functions Python 💜 +# Serverless Functions Python 💜 -A framework that provides tools when working with Scaleway Serverless Functions in Python. +Scaleway Serverless Functions is a framework to provide a good developer experience to write Serverless Functions. -## Installation +Serverless Functions make it easy to deploy, scale, and optimize your workloads on the cloud. + +Get started with Scaleway Functions (we support multiple languages :rocket:): + +- [Scaleway Serverless Functions Documentation](https://www.scaleway.com/en/docs/serverless/functions/quickstart/) +- [Scaleway Serverless Framework plugin](https://github.com/scaleway/serverless-scaleway-functions) +- [Scaleway Serverless Examples](https://github.com/scaleway/serverless-examples) +- [Scaleway Cloud Provider](https://scaleway.com) + +Testing frameworks for Scaleway Serverless Functions in other languages can be found here: + +- [Go](https://github.com/scaleway/serverless-functions-go) +- [Node](https://github.com/scaleway/serverless-functions-node) +- [PHP](https://github.com/scaleway/serverless-functions-php) +- [Rust](https://github.com/scaleway/serverless-functions-rust) + +## ⚙️ Quickstart You can use `pip` to install the framework: @@ -10,7 +26,29 @@ You can use `pip` to install the framework: pip install scaleway-functions-python ``` -## Usage +```python +def handler(event, context): + return "Hello World!" + +if __name__ == "__main__": + from scaleway_functions_python import serve_handler_locally + serve_handler_locally(handler) +``` + +For advanced usage please check the [usage section](#📦-Usage). + +## 🛟 Help & support + +- Scaleway support is available on Scaleway Console. +- Additionally, you can join our [Slack Community](https://www.scaleway.com/en/docs/tutorials/scaleway-slack-community/) + +## 🎓 Contributing + +We welcome all contributions to our open-source projects, please see our [contributing guidelines](docs/CONTRIBUTING.md). + +Do not hesitate to raise issues and pull requests we will have a look at them. + +## 📦 Usage ### 🏡 Local testing @@ -46,11 +84,6 @@ The framework provides some types hints to make it easier to develop your handle Check out the examples to get started! -## 🛟 Help & support - -- Scaleway support is available on Scaleway Console. -- Additionally, you can join our [Slack Community](https://www.scaleway.com/en/docs/tutorials/scaleway-slack-community/) - ## ❓ FAQ **Why do I need an additional package to call my function?** @@ -66,10 +99,16 @@ this tool has been developed to simulate this part. **Do I need to deploy my function differently?** -No. This framework does not affect deployment or performance. +No. This framework does not affect deployment nor performance. -## 🎓 Contributing +## Development -We welcome all contributions to our open-source projects, please see our contributing guidelines. +This repository is at its early stage and is still in active development. +If you are looking for a way to contribute please read [CONTRIBUTING.md](./docs/CONTRIBUTING.md). -Do not hesitate to raise issues and pull requests we will have a look at them. +## Reach Us + +We love feedback. +Don't hesitate to open a [Github issue](https://github.com/scaleway/serverless-functions-python/issues/new) or +feel free to reach us on [Scaleway Slack community](https://slack.scaleway.com/), +we are waiting for you on [#serverless-functions](https://scaleway-community.slack.com/app_redirect?channel=serverless-functions). From d245c8b826fddf64fa0ea85d2db9663eb459098f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Mon, 27 Feb 2023 18:01:50 +0100 Subject: [PATCH 21/26] docs: add contributing from serverless go --- docs/CODE_OF_CONDUCT.md | 76 ++++++++++++++++++++++++++++++++++++++ docs/CONTRIBUTING.md | 82 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 docs/CODE_OF_CONDUCT.md create mode 100644 docs/CONTRIBUTING.md diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d9c8871 --- /dev/null +++ b/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when +an individual is representing the project or its community in public spaces. +Examples of representing a project or community include using an official +project e-mail address, posting via an official social media account, or acting +as an appointed representative at an online or offline event. Representation of +a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at opensource@scaleway.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..66d641e --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,82 @@ +# Contribute to `serverless-functions-python` + +## Topics + +- [Contribute to `serverless-functions-python`](#contribute-to-serverless-functions-python) + - [Topics](#topics) + - [Reporting security issues](#reporting-security-issues) + - [Reporting issues](#reporting-issues) + - [Suggesting a feature](#suggesting-a-feature) + - [Contributing code](#contributing-code) + - [Submit code](#submit-code) + - [Pull Request Guidelines](#pull-request-guidelines) + - [Community guidelines](#community-guidelines) + +## Reporting security issues + +At Scaleway we take security seriously. If you have any issue regarding security, +please notify us by sending an email to security@scaleway.com. + +Please DO NOT create a GitHub issue. + +We will follow up with you promptly with more information and a plan for remediation. +We currently do not offer a paid security bounty program, but we would love to send some +Scaleway swag your way along with our deepest gratitude for your assistance in making +Scaleway a more secure Cloud ecosystem. + +## Reporting issues + +A great way to contribute to the project is to send a detailed report when you encounter a bug. +We always appreciate a well-written, thorough bug report, and will thank you for it! +Before opening a new issue, we appreciate you reviewing open issues to see if there are any similar requests. +If there is a match, thumbs up the issue with a 👍 and leave a comment if you have additional information. + +When reporting an issue, please include the version your are using in `go.mod` file. + +## Suggesting a feature + +When requesting a feature, some of the questions we want to answer are: + +- What value does this feature bring to end users? +- How urgent is the need (nice to have feature or need to have)? +- Does this align with the goals of this library? + +## Contributing code + +### Submit code + +To submit code: + +- Create a fork of the project +- Create a topic branch from where you want to base your work (usually main) +- Add tests to cover contributed code +- Push your commit(s) to your topic branch on your fork +- Open a pull request against `serverless-functions-python` `main` branch that follows [PR guidelines](#pull-request-guidelines) + +The maintainers of `serverless-functions-python` use a "Let's Gamble Try Merging" (LGTM) message in the pull request to note that the commits are ready to merge. +After one or more maintainer states LGTM, we will merge. +If you have questions or comments on your code, feel free to correct these in your branch through new commits. + +### Pull Request Guidelines + +The goal of the following guidelines is to have Pull Requests (PRs) that are fairly easy to review and comprehend, and code that is easy to maintain in the future. + +- **Pull Request title should respect [conventional commits](https://www.conventionalcommits.org/en/v1.0.0) specifications** and be clear on what is being changed. + - A fix for local testing will be titled `fix(local-testing): ...` + - A fix for http requests will be titled `fix(http): ...` + +- **Keep it readable for human reviewers** and prefer a subset of functionality (code) with tests and documentation over delivering them separately + +- **Notify Work In Progress PRs** by prefixing the title with `[WIP]` +- **Please, keep us updated.** + We will try our best to merge your PR, but please notice that PRs may be closed after 30 days of inactivity. + +Your pull request should be rebased against the `main` branch. + +Keep in mind only the **pull request title** will be used as commit message as we stash all commits on merge. + +## Community guidelines + +See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). + +Thank you for reading through all of this, if you have any question feel free to [reach us](../README.md#reach-us)! From 86750ce6afffb2b973a53bfd3c01ecc3724b0840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Tue, 28 Feb 2023 08:39:34 +0100 Subject: [PATCH 22/26] docs: update contributing --- docs/CONTRIBUTING.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 66d641e..f26d7e6 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -10,16 +10,16 @@ - [Contributing code](#contributing-code) - [Submit code](#submit-code) - [Pull Request Guidelines](#pull-request-guidelines) - - [Community guidelines](#community-guidelines) + - [Community Guidelines](#community-guidelines) ## Reporting security issues -At Scaleway we take security seriously. If you have any issue regarding security, +At Scaleway we take security seriously. If you have any issues regarding security, please notify us by sending an email to security@scaleway.com. Please DO NOT create a GitHub issue. -We will follow up with you promptly with more information and a plan for remediation. +We will follow up with you promptly with more information and a remediation plan. We currently do not offer a paid security bounty program, but we would love to send some Scaleway swag your way along with our deepest gratitude for your assistance in making Scaleway a more secure Cloud ecosystem. @@ -31,7 +31,7 @@ We always appreciate a well-written, thorough bug report, and will thank you for Before opening a new issue, we appreciate you reviewing open issues to see if there are any similar requests. If there is a match, thumbs up the issue with a 👍 and leave a comment if you have additional information. -When reporting an issue, please include the version your are using in `go.mod` file. +When reporting an issue, please include the PyPI version number of `scaleway-functions-python` that you are using. ## Suggesting a feature @@ -53,7 +53,7 @@ To submit code: - Push your commit(s) to your topic branch on your fork - Open a pull request against `serverless-functions-python` `main` branch that follows [PR guidelines](#pull-request-guidelines) -The maintainers of `serverless-functions-python` use a "Let's Gamble Try Merging" (LGTM) message in the pull request to note that the commits are ready to merge. +The maintainers of `serverless-functions-python` use a "Let's Get This Merged" (LGTM) message in the pull request to note that the commits are ready to merge. After one or more maintainer states LGTM, we will merge. If you have questions or comments on your code, feel free to correct these in your branch through new commits. @@ -73,10 +73,10 @@ The goal of the following guidelines is to have Pull Requests (PRs) that are fai Your pull request should be rebased against the `main` branch. -Keep in mind only the **pull request title** will be used as commit message as we stash all commits on merge. +Keep in mind only the **pull request title** will be used as the commit message as we stash all commits on merge. -## Community guidelines +## Community Guidelines See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). -Thank you for reading through all of this, if you have any question feel free to [reach us](../README.md#reach-us)! +Thank you for reading through all of this, if you have any questions feel free to [reach us](../README.md#reach-us)! From e011b4fdac56eee24d7af18d8485c0d007e1b82e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Tue, 28 Feb 2023 08:51:49 +0100 Subject: [PATCH 23/26] docs: readme remove duplicated sections --- README.md | 67 ++++++++++++------------------------------------------- 1 file changed, 14 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 531bf1c..1775f09 100644 --- a/README.md +++ b/README.md @@ -4,21 +4,7 @@ Scaleway Serverless Functions is a framework to provide a good developer experie Serverless Functions make it easy to deploy, scale, and optimize your workloads on the cloud. -Get started with Scaleway Functions (we support multiple languages :rocket:): - -- [Scaleway Serverless Functions Documentation](https://www.scaleway.com/en/docs/serverless/functions/quickstart/) -- [Scaleway Serverless Framework plugin](https://github.com/scaleway/serverless-scaleway-functions) -- [Scaleway Serverless Examples](https://github.com/scaleway/serverless-examples) -- [Scaleway Cloud Provider](https://scaleway.com) - -Testing frameworks for Scaleway Serverless Functions in other languages can be found here: - -- [Go](https://github.com/scaleway/serverless-functions-go) -- [Node](https://github.com/scaleway/serverless-functions-node) -- [PHP](https://github.com/scaleway/serverless-functions-php) -- [Rust](https://github.com/scaleway/serverless-functions-rust) - -## ⚙️ Quickstart +## ⚙️ Installation You can use `pip` to install the framework: @@ -26,28 +12,6 @@ You can use `pip` to install the framework: pip install scaleway-functions-python ``` -```python -def handler(event, context): - return "Hello World!" - -if __name__ == "__main__": - from scaleway_functions_python import serve_handler_locally - serve_handler_locally(handler) -``` - -For advanced usage please check the [usage section](#📦-Usage). - -## 🛟 Help & support - -- Scaleway support is available on Scaleway Console. -- Additionally, you can join our [Slack Community](https://www.scaleway.com/en/docs/tutorials/scaleway-slack-community/) - -## 🎓 Contributing - -We welcome all contributions to our open-source projects, please see our [contributing guidelines](docs/CONTRIBUTING.md). - -Do not hesitate to raise issues and pull requests we will have a look at them. - ## 📦 Usage ### 🏡 Local testing @@ -70,6 +34,8 @@ if __name__ == "__main__": serve_handler_locally(handler, port=8080) ``` +This adds an entry point to your Python script to run your Serverless handler locally. + ```console $ python handler.py $ curl http://localhost:8080 @@ -82,29 +48,24 @@ $ curl -X POST http://localhost:8080 The framework provides some types hints to make it easier to develop your handler. See this [example](examples/mirror.py) for more information on how to use them. -Check out the examples to get started! - -## ❓ FAQ - -**Why do I need an additional package to call my function?** +## Resources -Your Function Handler can be served by a simple HTTP server but Serverless Ecosystem involves a lot of different layers -and this package aims to simulate everything your request will go through. +Get started with Scaleway Functions: -**How my function will be deployed** +- [Scaleway Serverless Functions Documentation](https://www.scaleway.com/en/docs/serverless/functions/quickstart/) +- [Scaleway Serverless Framework plugin](https://github.com/scaleway/serverless-scaleway-functions) +- [Scaleway Serverless Examples](https://github.com/scaleway/serverless-examples) +- [Scaleway Cloud Provider](https://scaleway.com) -Your function will be deployed in an environment that allows your function to easily Scale up and down and it's wrapped into -different pieces of software with different roles. This stack also changes the headers, input and output of your function, that's why -this tool has been developed to simulate this part. +Testing frameworks for Scaleway Serverless Functions in other languages can be found here: -**Do I need to deploy my function differently?** +- [Go](https://github.com/scaleway/serverless-functions-go) -No. This framework does not affect deployment nor performance. +## 🎓 Contributing -## Development +We welcome all contributions to our open-source projects, please see our [contributing guidelines](docs/CONTRIBUTING.md). -This repository is at its early stage and is still in active development. -If you are looking for a way to contribute please read [CONTRIBUTING.md](./docs/CONTRIBUTING.md). +Do not hesitate to raise issues and pull requests we will have a look at them. ## Reach Us From efa4d50fc12a9d120a98cec41323127fd4a896a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Tue, 28 Feb 2023 10:35:58 +0100 Subject: [PATCH 24/26] docs: update readme --- README.md | 4 ++-- docs/CONTRIBUTING.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1775f09..0792cb5 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ $ curl -X POST http://localhost:8080 The framework provides some types hints to make it easier to develop your handler. See this [example](examples/mirror.py) for more information on how to use them. -## Resources +## 🌍 Resources Get started with Scaleway Functions: @@ -67,7 +67,7 @@ We welcome all contributions to our open-source projects, please see our [contri Do not hesitate to raise issues and pull requests we will have a look at them. -## Reach Us +## 💜 Reach Us We love feedback. Don't hesitate to open a [Github issue](https://github.com/scaleway/serverless-functions-python/issues/new) or diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index f26d7e6..70c0c51 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -79,4 +79,4 @@ Keep in mind only the **pull request title** will be used as the commit message See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). -Thank you for reading through all of this, if you have any questions feel free to [reach us](../README.md#reach-us)! +Thank you for reading through all of this, if you have any questions feel free to [reach us](../README.md#💜-reach-us)! From be40eff1a0ffac4c4e4102bfb2416d141d08841d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Tue, 28 Feb 2023 14:13:26 +0100 Subject: [PATCH 25/26] refactor: apply review suggestions --- .github/CODE_OF_CONDUCT.md | 76 ++++++++++++++++++++++++++ .github/CONTRIBUTING.md | 82 ++++++++++++++++++++++++++++ .github/dependabot.yml | 3 +- .github/workflows/pytest.yml | 5 +- .github/workflows/python-publish.yml | 13 +---- .gitignore | 34 ------------ README.md | 30 ++++------ 7 files changed, 175 insertions(+), 68 deletions(-) create mode 100644 .github/CODE_OF_CONDUCT.md create mode 100644 .github/CONTRIBUTING.md diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d9c8871 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when +an individual is representing the project or its community in public spaces. +Examples of representing a project or community include using an official +project e-mail address, posting via an official social media account, or acting +as an appointed representative at an online or offline event. Representation of +a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at opensource@scaleway.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..70c0c51 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,82 @@ +# Contribute to `serverless-functions-python` + +## Topics + +- [Contribute to `serverless-functions-python`](#contribute-to-serverless-functions-python) + - [Topics](#topics) + - [Reporting security issues](#reporting-security-issues) + - [Reporting issues](#reporting-issues) + - [Suggesting a feature](#suggesting-a-feature) + - [Contributing code](#contributing-code) + - [Submit code](#submit-code) + - [Pull Request Guidelines](#pull-request-guidelines) + - [Community Guidelines](#community-guidelines) + +## Reporting security issues + +At Scaleway we take security seriously. If you have any issues regarding security, +please notify us by sending an email to security@scaleway.com. + +Please DO NOT create a GitHub issue. + +We will follow up with you promptly with more information and a remediation plan. +We currently do not offer a paid security bounty program, but we would love to send some +Scaleway swag your way along with our deepest gratitude for your assistance in making +Scaleway a more secure Cloud ecosystem. + +## Reporting issues + +A great way to contribute to the project is to send a detailed report when you encounter a bug. +We always appreciate a well-written, thorough bug report, and will thank you for it! +Before opening a new issue, we appreciate you reviewing open issues to see if there are any similar requests. +If there is a match, thumbs up the issue with a 👍 and leave a comment if you have additional information. + +When reporting an issue, please include the PyPI version number of `scaleway-functions-python` that you are using. + +## Suggesting a feature + +When requesting a feature, some of the questions we want to answer are: + +- What value does this feature bring to end users? +- How urgent is the need (nice to have feature or need to have)? +- Does this align with the goals of this library? + +## Contributing code + +### Submit code + +To submit code: + +- Create a fork of the project +- Create a topic branch from where you want to base your work (usually main) +- Add tests to cover contributed code +- Push your commit(s) to your topic branch on your fork +- Open a pull request against `serverless-functions-python` `main` branch that follows [PR guidelines](#pull-request-guidelines) + +The maintainers of `serverless-functions-python` use a "Let's Get This Merged" (LGTM) message in the pull request to note that the commits are ready to merge. +After one or more maintainer states LGTM, we will merge. +If you have questions or comments on your code, feel free to correct these in your branch through new commits. + +### Pull Request Guidelines + +The goal of the following guidelines is to have Pull Requests (PRs) that are fairly easy to review and comprehend, and code that is easy to maintain in the future. + +- **Pull Request title should respect [conventional commits](https://www.conventionalcommits.org/en/v1.0.0) specifications** and be clear on what is being changed. + - A fix for local testing will be titled `fix(local-testing): ...` + - A fix for http requests will be titled `fix(http): ...` + +- **Keep it readable for human reviewers** and prefer a subset of functionality (code) with tests and documentation over delivering them separately + +- **Notify Work In Progress PRs** by prefixing the title with `[WIP]` +- **Please, keep us updated.** + We will try our best to merge your PR, but please notice that PRs may be closed after 30 days of inactivity. + +Your pull request should be rebased against the `main` branch. + +Keep in mind only the **pull request title** will be used as the commit message as we stash all commits on merge. + +## Community Guidelines + +See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). + +Thank you for reading through all of this, if you have any questions feel free to [reach us](../README.md#💜-reach-us)! diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f669372..0f545c8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,8 +2,7 @@ version: 2 updates: - package-ecosystem: github-actions - # Workflow files stored in the - # default location of `.github/workflows` + # Workflow files stored in the default location of `.github/workflows` directory: / schedule: interval: weekly diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 158816e..a86aa4f 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -14,7 +14,7 @@ jobs: test: strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ['3.8', '3.9', '3.10', '3.11'] runs-on: ubuntu-22.04 steps: @@ -39,8 +39,7 @@ jobs: - name: Test with pytest working-directory: tests - run: - poetry run pytest --junitxml=junit/test-results-${{ matrix.python-version + run: poetry run pytest --junitxml=junit/test-results-${{ matrix.python-version }}.xml - name: Upload pytest report diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index e45d2b8..4e30425 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,11 +1,4 @@ --- -# This workflow will upload a Python Package using Twine when a release is created -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries - -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. name: python-publish @@ -26,13 +19,13 @@ jobs: id: setup-python uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: '3.11' - name: Set up Poetry uses: ./.github/actions/setup-poetry with: - groups: "" # will only install the main group - python-version: "3.11" + groups: '' # will only install the main group + python-version: '3.11' - name: Publish package run: poetry publish --build diff --git a/.gitignore b/.gitignore index e325b94..6fa5db6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,48 +2,14 @@ # Byte-compiled / optimized / DLL files __pycache__/ -*.py[cod] -*$py.class # Distribution / packaging dist/ -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - # Unit test / coverage reports .coverage -.coverage.* .cache .pytest_cache/ -cover/ - -# Flask stuff: -instance/ -.webassets-cache - -# Sphinx documentation -docs/_build/ - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ # mypy .mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ diff --git a/README.md b/README.md index 0792cb5..4a6c93a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ # Serverless Functions Python 💜 -Scaleway Serverless Functions is a framework to provide a good developer experience to write Serverless Functions. +This repo contains utilities for testing your Python functions for Scaleway Serverless Functions. -Serverless Functions make it easy to deploy, scale, and optimize your workloads on the cloud. - -## ⚙️ Installation +## ⚙️ Quick Start You can use `pip` to install the framework: @@ -12,17 +10,11 @@ You can use `pip` to install the framework: pip install scaleway-functions-python ``` -## 📦 Usage - -### 🏡 Local testing - -When working with Serverless functions, it can be hard to test your function without deploying it. The framework provides a utility function that will run your handler locally: - ```python -# In handler.py +# handler.py -# Define your Serverless Handler. -def handler(event, _context): +# Standard entrypoint to a Scaleway serverless function +def handler(event, context): if event["method"] != "GET": return {"statusCode": 405, "body": "Invalid method!"} return "Hello World!" @@ -34,7 +26,7 @@ if __name__ == "__main__": serve_handler_locally(handler, port=8080) ``` -This adds an entry point to your Python script to run your Serverless handler locally. +You can then run your function locally: ```console $ python handler.py @@ -44,7 +36,7 @@ $ curl -X POST http://localhost:8080 > Invalid method! ``` -### 🧱 Type hints +## 🧱 Type hints The framework provides some types hints to make it easier to develop your handler. See this [example](examples/mirror.py) for more information on how to use them. @@ -69,7 +61,7 @@ Do not hesitate to raise issues and pull requests we will have a look at them. ## 💜 Reach Us -We love feedback. -Don't hesitate to open a [Github issue](https://github.com/scaleway/serverless-functions-python/issues/new) or -feel free to reach us on [Scaleway Slack community](https://slack.scaleway.com/), -we are waiting for you on [#serverless-functions](https://scaleway-community.slack.com/app_redirect?channel=serverless-functions). +We love feedback. Feel free to: + +- Open a [Github issue](https://github.com/scaleway/serverless-functions-python/issues/new) +- Send us a message on the [Scaleway Slack community](https://slack.scaleway.com/), in the [#serverless-functions](https://scaleway-community.slack.com/app_redirect?channel=serverless-functions) channel. From 2fe2502ef1fba7dfeb06184bcd5f3a7529b2599c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Tue, 28 Feb 2023 14:23:30 +0100 Subject: [PATCH 26/26] chore: delete docs folder --- docs/CODE_OF_CONDUCT.md | 76 -------------------------------------- docs/CONTRIBUTING.md | 82 ----------------------------------------- 2 files changed, 158 deletions(-) delete mode 100644 docs/CODE_OF_CONDUCT.md delete mode 100644 docs/CONTRIBUTING.md diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md deleted file mode 100644 index d9c8871..0000000 --- a/docs/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,76 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or - advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic - address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies within all project spaces, and it also applies when -an individual is representing the project or its community in public spaces. -Examples of representing a project or community include using an official -project e-mail address, posting via an official social media account, or acting -as an appointed representative at an online or offline event. Representation of -a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at opensource@scaleway.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md deleted file mode 100644 index 70c0c51..0000000 --- a/docs/CONTRIBUTING.md +++ /dev/null @@ -1,82 +0,0 @@ -# Contribute to `serverless-functions-python` - -## Topics - -- [Contribute to `serverless-functions-python`](#contribute-to-serverless-functions-python) - - [Topics](#topics) - - [Reporting security issues](#reporting-security-issues) - - [Reporting issues](#reporting-issues) - - [Suggesting a feature](#suggesting-a-feature) - - [Contributing code](#contributing-code) - - [Submit code](#submit-code) - - [Pull Request Guidelines](#pull-request-guidelines) - - [Community Guidelines](#community-guidelines) - -## Reporting security issues - -At Scaleway we take security seriously. If you have any issues regarding security, -please notify us by sending an email to security@scaleway.com. - -Please DO NOT create a GitHub issue. - -We will follow up with you promptly with more information and a remediation plan. -We currently do not offer a paid security bounty program, but we would love to send some -Scaleway swag your way along with our deepest gratitude for your assistance in making -Scaleway a more secure Cloud ecosystem. - -## Reporting issues - -A great way to contribute to the project is to send a detailed report when you encounter a bug. -We always appreciate a well-written, thorough bug report, and will thank you for it! -Before opening a new issue, we appreciate you reviewing open issues to see if there are any similar requests. -If there is a match, thumbs up the issue with a 👍 and leave a comment if you have additional information. - -When reporting an issue, please include the PyPI version number of `scaleway-functions-python` that you are using. - -## Suggesting a feature - -When requesting a feature, some of the questions we want to answer are: - -- What value does this feature bring to end users? -- How urgent is the need (nice to have feature or need to have)? -- Does this align with the goals of this library? - -## Contributing code - -### Submit code - -To submit code: - -- Create a fork of the project -- Create a topic branch from where you want to base your work (usually main) -- Add tests to cover contributed code -- Push your commit(s) to your topic branch on your fork -- Open a pull request against `serverless-functions-python` `main` branch that follows [PR guidelines](#pull-request-guidelines) - -The maintainers of `serverless-functions-python` use a "Let's Get This Merged" (LGTM) message in the pull request to note that the commits are ready to merge. -After one or more maintainer states LGTM, we will merge. -If you have questions or comments on your code, feel free to correct these in your branch through new commits. - -### Pull Request Guidelines - -The goal of the following guidelines is to have Pull Requests (PRs) that are fairly easy to review and comprehend, and code that is easy to maintain in the future. - -- **Pull Request title should respect [conventional commits](https://www.conventionalcommits.org/en/v1.0.0) specifications** and be clear on what is being changed. - - A fix for local testing will be titled `fix(local-testing): ...` - - A fix for http requests will be titled `fix(http): ...` - -- **Keep it readable for human reviewers** and prefer a subset of functionality (code) with tests and documentation over delivering them separately - -- **Notify Work In Progress PRs** by prefixing the title with `[WIP]` -- **Please, keep us updated.** - We will try our best to merge your PR, but please notice that PRs may be closed after 30 days of inactivity. - -Your pull request should be rebased against the `main` branch. - -Keep in mind only the **pull request title** will be used as the commit message as we stash all commits on merge. - -## Community Guidelines - -See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). - -Thank you for reading through all of this, if you have any questions feel free to [reach us](../README.md#💜-reach-us)!