From c61464fb93677020bb27a158d81ceaf031aa936c Mon Sep 17 00:00:00 2001 From: Tomas Nilsson Date: Thu, 10 Oct 2024 14:28:14 +0000 Subject: [PATCH] feat: replace hatch with poetry - Also update grpcio to latest version (1.66.2) - Also update brotobuf to latest version (5.28) - Also update brotobuf compiler to latest version (28.2). It is not entirely clear how protobuf compiler relates to the protobuf python library --- .github/workflows/build-docs-mypy.yaml | 30 - .../build-remotivelabs-broker-ci.yaml | 58 + .github/workflows/code-qa.yaml | 56 - .github/workflows/python-code-qa-ci.yaml | 41 + .github/workflows/rust-code-qa-ci.yaml | 24 + .python-version | 2 +- README.md | 42 +- grpc-web/README.md | 63 +- grpc-web/grpc-web-stubs/README.md | 41 +- grpc-web/grpc-web-stubs/examples/README.md | 1 + python/README.md | 81 +- python/remotivelabs-broker/.pylintrc | 640 --------- python/remotivelabs-broker/.ruff.toml | 76 -- python/remotivelabs-broker/README.md | 57 +- python/remotivelabs-broker/docker-build.sh | 23 +- python/remotivelabs-broker/docker/Dockerfile | 54 +- .../docker/build-all-in-docker.sh | 70 - python/remotivelabs-broker/docker/build.sh | 111 ++ .../docker/download_protoc.sh | 43 +- .../docker/download_protoc_gen_doc.sh | 41 + .../remotivelabs-broker/docker/entrypoint.sh | 44 + .../misc/fix_import_statements.py | 5 + python/remotivelabs-broker/poetry.lock | 1172 +++++++++++++++++ python/remotivelabs-broker/poetry.toml | 2 + python/remotivelabs-broker/pyproject.toml | 178 ++- .../remotivelabs/broker/__about__.py | 6 +- .../remotivelabs/broker/__init__.py | 56 +- .../remotivelabs/broker/_log.py | 11 + .../remotivelabs/broker/sync/__init__.py | 23 +- .../remotivelabs/broker/sync/client.py | 19 +- .../remotivelabs/broker/sync/helper.py | 69 +- .../remotivelabs/broker/sync/signalcreator.py | 49 +- python/remotivelabs-broker/tests/__init__.py | 3 - python/remotivelabs-broker/tests/test_live.py | 2 - rust/README.md | 28 + rust/remotivelabs-broker/Cargo.lock | 2 +- rust/remotivelabs-broker/Cargo.toml | 12 +- rust/remotivelabs-broker/README.md | 21 +- rust/remotivelabs-broker/build.rs | 2 +- rust/remotivelabs-broker/examples/README.md | 1 + .../examples/pub_client.rs | 4 +- .../examples/sub_client.rs | 4 +- .../remotivelabs-broker/examples/subscribe.rs | 4 +- .../{remotive_api => generated}/.gitignore | 0 .../src/{remotive_api => generated}/mod.rs | 0 rust/remotivelabs-broker/src/lib.rs | 8 +- 46 files changed, 2021 insertions(+), 1258 deletions(-) delete mode 100644 .github/workflows/build-docs-mypy.yaml create mode 100644 .github/workflows/build-remotivelabs-broker-ci.yaml delete mode 100644 .github/workflows/code-qa.yaml create mode 100644 .github/workflows/python-code-qa-ci.yaml create mode 100644 .github/workflows/rust-code-qa-ci.yaml create mode 100644 grpc-web/grpc-web-stubs/examples/README.md delete mode 100644 python/remotivelabs-broker/.pylintrc delete mode 100644 python/remotivelabs-broker/.ruff.toml delete mode 100755 python/remotivelabs-broker/docker/build-all-in-docker.sh create mode 100755 python/remotivelabs-broker/docker/build.sh create mode 100644 python/remotivelabs-broker/docker/download_protoc_gen_doc.sh create mode 100755 python/remotivelabs-broker/docker/entrypoint.sh create mode 100644 python/remotivelabs-broker/poetry.lock create mode 100644 python/remotivelabs-broker/poetry.toml create mode 100644 python/remotivelabs-broker/remotivelabs/broker/_log.py delete mode 100644 python/remotivelabs-broker/tests/__init__.py create mode 100644 rust/README.md create mode 100644 rust/remotivelabs-broker/examples/README.md rename rust/remotivelabs-broker/src/{remotive_api => generated}/.gitignore (100%) rename rust/remotivelabs-broker/src/{remotive_api => generated}/mod.rs (100%) diff --git a/.github/workflows/build-docs-mypy.yaml b/.github/workflows/build-docs-mypy.yaml deleted file mode 100644 index 6803c53..0000000 --- a/.github/workflows/build-docs-mypy.yaml +++ /dev/null @@ -1,30 +0,0 @@ -name: Doc builder and mypy - -on: push - -jobs: - build-docs: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Build docs - env: - NO_TTY: true - run: | - cd python/remotivelabs-broker - ./docker-build.sh - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: 3.8 - architecture: x64 - - name: Install mypy - run: | - pip install mypy - pip install python/remotivelabs-broker - pip install python/remotivelabs-broker[default] - - name: Run mypy - run: | - mypy python/remotivelabs-broker/remotivelabs/ - mypy . --exclude python/remotivelabs-broker/remotivelabs/ diff --git a/.github/workflows/build-remotivelabs-broker-ci.yaml b/.github/workflows/build-remotivelabs-broker-ci.yaml new file mode 100644 index 0000000..43b4c46 --- /dev/null +++ b/.github/workflows/build-remotivelabs-broker-ci.yaml @@ -0,0 +1,58 @@ +name: Build remotivelabs-broker package and documentation + +on: push + +jobs: + build: + name: Build remotivelabs-broker + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Build package and docs + env: + NO_TTY: true + run: ./python/remotivelabs-broker/docker-build.sh + - id: build_output + run: echo "whl_path=$(ls python/remotivelabs-broker/dist/*.whl)" >> $GITHUB_OUTPUT + + - uses: actions/upload-artifact@v4 + with: + name: remotivelabs-broker-whl + path: ${{ steps.build_output.outputs.whl_path }} + if-no-files-found: error + retention-days: 1 + overwrite: true + + test: + name: Install remotivelabs-broker + needs: build + + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10"] + os: [ubuntu-22.04, ubuntu-24.04, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - uses: actions/download-artifact@v4 + with: + name: remotivelabs-broker-whl + + - id: download_artifact + run: echo "library_path=$(ls *.whl)" >> $GITHUB_OUTPUT + shell: bash + + - name: Install remotivelabs-broker + run: pip install ${{ steps.download_artifact.outputs.library_path }} + shell: bash diff --git a/.github/workflows/code-qa.yaml b/.github/workflows/code-qa.yaml deleted file mode 100644 index b1bc38e..0000000 --- a/.github/workflows/code-qa.yaml +++ /dev/null @@ -1,56 +0,0 @@ -name: Code-QA - -on: push - -jobs: - ruff-lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: chartboost/ruff-action@v1 - - ruff-format: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: chartboost/ruff-action@v1 - with: - src: "." - args: format --check --diff - - pylint: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: 3.8 - architecture: x64 - - name: Install pylint - run: | - pip install pylint - pip install python/remotivelabs-broker - pip install python/remotivelabs-broker[default] - - name: Run pylint - run: | - cd python/remotivelabs-broker - pylint **/*.py - - rust-cargo: - name: Rust cargo tasks - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - name: Build and run tests - run: | - pushd rust/remotivelabs-broker - cargo test - popd - - name: Check format - run: | - pushd rust/remotivelabs-broker - cargo fmt --check - popd diff --git a/.github/workflows/python-code-qa-ci.yaml b/.github/workflows/python-code-qa-ci.yaml new file mode 100644 index 0000000..7535fd8 --- /dev/null +++ b/.github/workflows/python-code-qa-ci.yaml @@ -0,0 +1,41 @@ +name: Python Code QA CI + +on: push + +jobs: + python-ci: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10"] + defaults: + run: + working-directory: ./python/remotivelabs-broker + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - uses: abatilo/actions-poetry@v2 + - run: poetry self add 'poethepoet[poetry_plugin]' + + - name: Generate stubs (and build package) + env: + NO_TTY: true + run: ./docker-build.sh + + - run: poetry install + + - name: run pytest + run: poetry poe test + + - name: run ruff + run: poetry poe lint + + - name: run pylint + run: poetry poe pylint + + - name: run mypy + run: poetry poe mypy diff --git a/.github/workflows/rust-code-qa-ci.yaml b/.github/workflows/rust-code-qa-ci.yaml new file mode 100644 index 0000000..c64d686 --- /dev/null +++ b/.github/workflows/rust-code-qa-ci.yaml @@ -0,0 +1,24 @@ +name: Rust Code QA CI + +on: push + +jobs: + rust-ci: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + + - name: Build and run tests + run: | + pushd rust/remotivelabs-broker + cargo test + popd + + - name: Check format + run: | + pushd rust/remotivelabs-broker + cargo fmt --check + popd diff --git a/.python-version b/.python-version index cc1923a..c8cfe39 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.8 +3.10 diff --git a/README.md b/README.md index 9fd8bdb..b73d0c4 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,31 @@ # RemotiveLabs RemotiveBroker GRPC APIs -This repo contains all public API from [RemotiveLabs](https://remotivelabs.com/) for integrating -with RemotiveBroker using your favourite programming language. +This repo contains all public API from [RemotiveLabs](https://remotivelabs.com/) for integrating with RemotiveBroker using your favourite +programming language. -We currently have pre-built GAPIC (Generated API Client) for python and grpc-web -but will add more moving forward. - -For other languages visit https://grpc.io/ to read up how to generate code for your -programming language based on our protocol buffer definition files +We currently have pre-built GAPIC (Generated API Client) for a few languages, but will add more moving forward. +For other languages visit https://grpc.io/ to read up how to generate code for your programming language based on our protocol buffer +definition files. ## Protocol buffer definitions Use these to generate GAPIC for your programming language. -- [Documentation and source code](protos/) - -## Python RemotiveBroker API - -Pre-built Python GAPIC + some extra helper functions - -- [Documentation and source code](python/remotivelabs-broker/) -- [Code samples](https://github.com/remotivelabs/remotivelabs-samples/tree/main/python) - - -## gRPC-web RemotiveBroker API +[Protobuf files](./protos/README.md) -Pre-built gRPC-web RemotiveBroker GAPIC. gRPC-web is designed to run in browser and -not in nodejs. This is Javascipt+Typescript. +## Language specific APIs -- [Documentation and source code](grpc-web/grpc-web-stubs) +- [Python](./python/remotivelabs-broker/) +- [gRPC-web](./grpc-web/README.md) +- [Rust](./rust/README.md) ## RemotiveBroker configuration schemas [JSON schemas](schemas) of configuration files used by RemotiveBroker. -## Coming soon - -Pre-built GAPIC for the following languages are coming shortly - -* Java and Kotlin -* NodeJS - ## Questions -Please use our discussion forum/community for any questions you might have
-https://github.com/remotivelabs/remotivelabs-community/discussions +Please use our discussion forum/community for any questions you might have: +https://github.com/remotivelabs/remotivelabs-community/discussions diff --git a/grpc-web/README.md b/grpc-web/README.md index 57af5e4..2b23f74 100644 --- a/grpc-web/README.md +++ b/grpc-web/README.md @@ -1,26 +1,57 @@ -# RemotiveLabs WEB-GRPC +# RemotiveBroker WEB-GRPC API -Web-grpc is javascript to be used in a browser context, not intended -to bu used with nodejs, read more here https://github.com/grpc/grpc-web +`remotivelabs-grpc-web-stubs` - Javascript SDK for interacting with the RemotiveBroker API in a browser context. Not intended to be used +with NodeJS. -## Grpc-web-stubs +Published to npm on [https://www.npmjs.com/package/remotivelabs-grpc-web-stubs](https://www.npmjs.com/package/remotivelabs-grpc-web-stubs). -[![npm version](https://img.shields.io/npm/v/remotivelabs-grpc-web-stubs.svg)](https://www.npmjs.com/package/remotivelabs-grpc-web-stubs) +## Getting started -Pre-built GRPC stubs generated from protobuf files +```bash +cd grpc-web/grpc-web-stubs +# install dependencies +yarn install + +# TODO ``` -npm install --save remotivelabs-grpc-web-stubs -``` -or -``` -yarn add remotivelabs-grpc-web-stubs + +## Building + +```bash +cd grpc-web/grpc-web-stubs + +# Build docker image +docker build -t remotivelabs/grpc-web-generator . + +# Generate typescript +./generate-ts.sh + +# Generate javascript +./generate-js.sh ``` -Read more: [grpc-web-stubs/](grpc-web-stubs/) +## Versioning -## Grpc-web-client +Versioning is done using `npm version`, see [Publishing](#publishing). -RemotiveBroker high-level client is coming soon. This API will be based on our -RemotiveBrokerApp that is using the grpc-web-stubs but adds layer on top to make -it simpler to use. \ No newline at end of file +Follow [Semantic versioning](https://semver.org/). Beta versions should be suffixed with `-beta*`, example `0.2.0-beta1`. + +## Publishing + +Published to npm on [https://www.npmjs.com/package/remotivelabs-grpc-web-stubs](https://www.npmjs.com/package/remotivelabs-grpc-web-stubs). + +```bash +# generate stubs +./generate-ts.sh + +# update version +npm version x.y.z + +# commit version +git add . +git commit -m "release: Prepare a release for version x.y.z" + +# publish +npm publish +``` diff --git a/grpc-web/grpc-web-stubs/README.md b/grpc-web/grpc-web-stubs/README.md index 7b5d22d..bed3cce 100644 --- a/grpc-web/grpc-web-stubs/README.md +++ b/grpc-web/grpc-web-stubs/README.md @@ -5,44 +5,35 @@ These are generated grpc-web stubs to be used in a browser context, not intended to bu used with nodejs, read more here https://github.com/grpc/grpc-web -## Usage +## Installation -### Installation -``` -npm install --save remotivelabs-grpc-web-stubs +```bash +yarn install --save remotivelabs-grpc-web-stubs ``` + or -``` + +```bash yarn add remotivelabs-grpc-web-stubs ``` -### Import -``` +## Usage + +```javascript import {SystemServiceClient} from 'remotivelabs-grpc-web-stubs' const client = new SystemServiceClient(brokerUrl) ``` -## Development - -### Build grpc-web-generator +## Examples -This image is on dockerhub so you do not have to build it -```sh -docker build -t remotivelabs/grpc-web-generator . -``` - -### Generate stubs +See [examples](./examples/README.md) -From this directory run the following commands and update `src/index.ts` to explicitly export types. +## License -```sh -sh ./generate-ts.sh -``` +`remotivelabs-grpc-web-stubs` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license. -## Release Instructions +## Documentation -1. Commit changes. -2. Generate stubs `sh ./generate-ts.sh`. -3. Update version with `npm version x.y.z` and commit it with `release: Prepare a release for version x.y.z`. -4. Publish with `npm publish`. +TODO: We dont have any documentation +See [https://docs.remotivelabs.com/apis/python/remotivelabs/broker](https://docs.remotivelabs.com/apis/python/remotivelabs/broker). diff --git a/grpc-web/grpc-web-stubs/examples/README.md b/grpc-web/grpc-web-stubs/examples/README.md new file mode 100644 index 0000000..4f2254e --- /dev/null +++ b/grpc-web/grpc-web-stubs/examples/README.md @@ -0,0 +1 @@ +# `remotivelabs-grpc-web-stubs` examples diff --git a/python/README.md b/python/README.md index 98da2f7..ca3c963 100644 --- a/python/README.md +++ b/python/README.md @@ -1,60 +1,69 @@ -# RemotiveLabs Python libraries +# RemotiveBroker Python API -## Usage +`remotivelabs-broker` - Python SDK for interacting with the RemotiveBroker API. -Python RemotiveBroker API +Published to PyPI on [https://pypi.org/project/remotivelabs-broker/](https://pypi.org/project/remotivelabs-broker/). -https://pypi.org/project/remotivelabs-broker/ +## Getting started -Published on [PyPi](https://pypi.org/) with the prefix `remotivelabs-` and with the user [remotivelabs](https://pypi.org/user/remotivelabs/). -All packages use [Hatch](https://hatch.pypa.io/) for packaging and publishing. +Prerequisites: +```bash +# Install poetry (and optionally poe plugin to simplify poetry command execution) +pipx install poetry +poetry self add 'poethepoet[poetry_plugin]' +``` +Build and run: -## Development +```bash +cd python/remotivelabs-broker -Install hatch on your development computer: +# Install dependencies in a virtualenv +poetry install - pip install hatch +# Build the library (output in dist/) +poetry build -Any project related information is stored in `pyproject.toml`. +# Check (test, lint, check types) +poetry poe check -Hatch supplies a basic set of tools for development. -All operations should be done in an virtual environment created by hatch. +# run standard test suite +poetry run pytest -Go to the directory of the module which you are going to be working on. -For example: +# run tests against running broker +poetry run pytest -m server --broker +``` - cd python/remotivelabs-broker +If you need to (re)generate protobuf stubs, see [Building](#building). -Create a local environment. +## Building - hatch env create +Building the complete package, including protobuf stubs and documentation, is done using a docker container: -Start a shell in the environment. +```bash +./python/remotivelabs-broker/docker-build.sh +``` - hatch shell +## Versioning -While in this virtual environment the library is available as a python module without needing to be installed. +Update the package version by editing the following `pyproject.toml` file. -Build the library: +Follow [Semantic versioning](https://semver.org/). Beta versions should be suffixed with `-beta*`, example `0.2.0-beta1`. - hatch build +## Publishing -Update the package version by editing the file `__about__.py`. -This version stamp will be used in Pypi. -Follow [Semantic versioning](https://semver.org/). +Published to PyPI on [https://pypi.org/project/remotivelabs-broker/](https://pypi.org/project/remotivelabs-broker/): -Testing, with coverage: +All RemotiveLabs libraries: +- share the same `remotivelabs` [namespace package](https://peps.python.org/pep-0420/). +- use the `remotivelabs-` prefix in the library name. +- are published with the [remotivelabs](https://pypi.org/user/remotivelabs/) user. - hatch run cov - -Without coverage: - - hatch run no-cov - -While in the hatch virtual environment. -Run the Python debugger: - - python -m pdb ... +```bash +# Get token from Johan Rask +poetry config pypi-token.pypi +# find username and password in less secret location +poetry publish +``` diff --git a/python/remotivelabs-broker/.pylintrc b/python/remotivelabs-broker/.pylintrc deleted file mode 100644 index 1d2ae19..0000000 --- a/python/remotivelabs-broker/.pylintrc +++ /dev/null @@ -1,640 +0,0 @@ -[MAIN] - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Clear in-memory caches upon conclusion of linting. Useful if running pylint -# in a server-like mode. -clear-cache-post-run=no - -# Load and enable all available extensions. Use --list-extensions to see a list -# all available extensions. -#enable-all-extensions= - -# In error mode, messages with a category besides ERROR or FATAL are -# suppressed, and no reports are done by default. Error mode is compatible with -# disabling specific errors. -#errors-only= - -# Always return a 0 (non-error) status code, even if lint errors are found. -# This is primarily useful in continuous integration scripts. -#exit-zero= - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code. -extension-pkg-allow-list= - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code. (This is an alternative name to extension-pkg-allow-list -# for backward compatibility.) -extension-pkg-whitelist= - -# Return non-zero exit code if any of these messages/categories are detected, -# even if score is above --fail-under value. Syntax same as enable. Messages -# specified are enabled, while categories only check already-enabled messages. -fail-on= - -# Specify a score threshold under which the program will exit with error. -fail-under=10 - -# Interpret the stdin as a python script, whose filename needs to be passed as -# the module_or_package argument. -#from-stdin= - -# Files or directories to be skipped. They should be base names, not paths. -ignore=CVS - -# Add files or directories matching the regular expressions patterns to the -# ignore-list. The regex matches against paths and can be in Posix or Windows -# format. Because '\\' represents the directory delimiter on Windows systems, -# it can't be used as an escape character. -ignore-paths= - -# Files or directories matching the regular expression patterns are skipped. -# The regex matches against base names, not paths. The default value ignores -# Emacs file locks -ignore-patterns=\..* - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis). It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the -# number of processors available to use, and will cap the count on Windows to -# avoid hangs. -jobs=1 - -# Control the amount of potential inferred values when inferring a single -# object. This can help the performance when dealing with large functions or -# complex, nested conditions. -limit-inference-results=100 - -# List of plugins (as comma separated values of python module names) to load, -# usually to register additional checkers. -load-plugins= - -# Pickle collected data for later comparisons. -persistent=yes - -# Minimum Python version to use for version dependent checks. Will default to -# the version used to run pylint. -py-version=3.8 - -# Discover python modules and packages in the file system subtree. -recursive=no - -# Add paths to the list of the source roots. Supports globbing patterns. The -# source root is an absolute path or a path relative to the current working -# directory used to determine a package namespace for modules located under the -# source root. -source-roots= - -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages. -suggestion-mode=yes - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - -# In verbose mode, extra non-checker-related info will be displayed. -#verbose= - - -[BASIC] - -# Naming style matching correct argument names. -argument-naming-style=snake_case - -# Regular expression matching correct argument names. Overrides argument- -# naming-style. If left empty, argument names will be checked with the set -# naming style. -#argument-rgx= - -# Naming style matching correct attribute names. -attr-naming-style=snake_case - -# Regular expression matching correct attribute names. Overrides attr-naming- -# style. If left empty, attribute names will be checked with the set naming -# style. -#attr-rgx= - -# Bad variable names which should always be refused, separated by a comma. -bad-names=foo, - bar, - baz, - toto, - tutu, - tata - -# Bad variable names regexes, separated by a comma. If names match any regex, -# they will always be refused -bad-names-rgxs= - -# Naming style matching correct class attribute names. -class-attribute-naming-style=any - -# Regular expression matching correct class attribute names. Overrides class- -# attribute-naming-style. If left empty, class attribute names will be checked -# with the set naming style. -#class-attribute-rgx= - -# Naming style matching correct class constant names. -class-const-naming-style=UPPER_CASE - -# Regular expression matching correct class constant names. Overrides class- -# const-naming-style. If left empty, class constant names will be checked with -# the set naming style. -#class-const-rgx= - -# Naming style matching correct class names. -class-naming-style=PascalCase - -# Regular expression matching correct class names. Overrides class-naming- -# style. If left empty, class names will be checked with the set naming style. -#class-rgx= - -# Naming style matching correct constant names. -const-naming-style=UPPER_CASE - -# Regular expression matching correct constant names. Overrides const-naming- -# style. If left empty, constant names will be checked with the set naming -# style. -#const-rgx= - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Naming style matching correct function names. -function-naming-style=snake_case - -# Regular expression matching correct function names. Overrides function- -# naming-style. If left empty, function names will be checked with the set -# naming style. -#function-rgx= - -# Good variable names which should always be accepted, separated by a comma. -good-names=i, - j, - k, - ex, - Run, - _ - -# Good variable names regexes, separated by a comma. If names match any regex, -# they will always be accepted -good-names-rgxs= - -# Include a hint for the correct naming format with invalid-name. -include-naming-hint=no - -# Naming style matching correct inline iteration names. -inlinevar-naming-style=any - -# Regular expression matching correct inline iteration names. Overrides -# inlinevar-naming-style. If left empty, inline iteration names will be checked -# with the set naming style. -#inlinevar-rgx= - -# Naming style matching correct method names. -method-naming-style=snake_case - -# Regular expression matching correct method names. Overrides method-naming- -# style. If left empty, method names will be checked with the set naming style. -#method-rgx= - -# Naming style matching correct module names. -module-naming-style=snake_case - -# Regular expression matching correct module names. Overrides module-naming- -# style. If left empty, module names will be checked with the set naming style. -#module-rgx= - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -# These decorators are taken in consideration only for invalid-name. -property-classes=abc.abstractproperty - -# Regular expression matching correct type alias names. If left empty, type -# alias names will be checked with the set naming style. -#typealias-rgx= - -# Regular expression matching correct type variable names. If left empty, type -# variable names will be checked with the set naming style. -#typevar-rgx= - -# Naming style matching correct variable names. -variable-naming-style=snake_case - -# Regular expression matching correct variable names. Overrides variable- -# naming-style. If left empty, variable names will be checked with the set -# naming style. -#variable-rgx= - - -[CLASSES] - -# Warn about protected attribute access inside special methods -check-protected-access-in-special-methods=no - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__, - __new__, - setUp, - asyncSetUp, - __post_init__ - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[DESIGN] - -# List of regular expressions of class ancestor names to ignore when counting -# public methods (see R0903) -exclude-too-few-public-methods= - -# List of qualified class names to ignore when counting class parents (see -# R0901) -ignored-parents= - -# Maximum number of arguments for function / method. -max-args=7 - -# Maximum number of attributes for a class (see R0902). -max-attributes=10 - -# Maximum number of boolean expressions in an if statement (see R0916). -max-bool-expr=5 - -# Maximum number of branch for function / method body. -max-branches=12 - -# Maximum number of locals for function / method body. -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body. -max-returns=6 - -# Maximum number of statements in function / method body. -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when caught. -overgeneral-exceptions=builtins.BaseException,builtins.Exception - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=140 - -# Maximum number of lines in a module. -max-module-lines=1000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[IMPORTS] - -# List of modules that can be imported at any level, not just the top level -# one. -allow-any-import-level= - -# Allow explicit reexports by alias from a package __init__. -allow-reexport-from-package=no - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Deprecated modules which should not be used, separated by a comma. -deprecated-modules= - -# Output a graph (.gv or any supported image format) of external dependencies -# to the given file (report RP0402 must not be disabled). -ext-import-graph= - -# Output a graph (.gv or any supported image format) of all (i.e. internal and -# external) dependencies to the given file (report RP0402 must not be -# disabled). -import-graph= - -# Output a graph (.gv or any supported image format) of internal dependencies -# to the given file (report RP0402 must not be disabled). -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - -# Couples of modules and preferred modules, separated by a comma. -preferred-modules= - - -[LOGGING] - -# The type of string formatting that logging methods do. `old` means using % -# formatting, `new` is for `{}` formatting. -logging-format-style=old - -# Logging modules to check that the string format arguments are in logging -# function parameter format. -logging-modules=logging - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, -# UNDEFINED. -confidence=HIGH, - CONTROL_FLOW, - INFERENCE, - INFERENCE_FAILURE, - UNDEFINED - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once). You can also use "--disable=all" to -# disable everything first and then re-enable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use "--disable=all --enable=classes -# --disable=W". -disable=raw-checker-failed, - bad-inline-option, - locally-disabled, - file-ignored, - suppressed-message, - useless-suppression, - deprecated-pragma, - use-symbolic-message-instead, - use-implicit-booleaness-not-comparison-to-string, - use-implicit-booleaness-not-comparison-to-zero, - missing-function-docstring, - missing-class-docstring, - missing-module-docstring, - logging-fstring-interpolation, - broad-exception-raised, - too-few-public-methods - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable= - - -[METHOD_ARGS] - -# List of qualified names (i.e., library.method) which require a timeout -# parameter e.g. 'requests.api.get,requests.api.post' -timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME, - XXX, - TODO - -# Regular expression of note tags to take in consideration. -notes-rgx= - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - -# Complete name of functions that never returns. When checking for -# inconsistent-return-statements if a never returning function is called then -# it will be considered as an explicit return statement and no message will be -# printed. -never-returning-functions=sys.exit,argparse.parse_error - - -[REPORTS] - -# Python expression which should return a score less than or equal to 10. You -# have access to the variables 'fatal', 'error', 'warning', 'refactor', -# 'convention', and 'info' which contain the number of messages in each -# category, as well as 'statement' which is the total number of statements -# analyzed. This score is used by the global evaluation report (RP0004). -evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details. -msg-template= - -# Set the output format. Available formats are: text, parseable, colorized, -# json2 (improved json format), json (old json format) and msvs (visual -# studio). You can also give a reporter class, e.g. -# mypackage.mymodule.MyReporterClass. -#output-format= - -# Tells whether to display a full report or only the messages. -reports=no - -# Activate the evaluation score. -score=yes - - -[SIMILARITIES] - -# Comments are removed from the similarity computation -ignore-comments=yes - -# Docstrings are removed from the similarity computation -ignore-docstrings=yes - -# Imports are removed from the similarity computation -ignore-imports=yes - -# Signatures are removed from the similarity computation -ignore-signatures=yes - -# Minimum lines number of a similarity. -min-similarity-lines=4 - - -[SPELLING] - -# Limits count of emitted suggestions for spelling mistakes. -max-spelling-suggestions=4 - -# Spelling dictionary name. No available dictionaries : You need to install -# both the python package and the system dependency for enchant to work. -spelling-dict= - -# List of comma separated words that should be considered directives if they -# appear at the beginning of a comment and should not be checked. -spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains the private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to the private dictionary (see the -# --spelling-private-dict-file option) instead of raising a message. -spelling-store-unknown-words=no - - -[STRING] - -# This flag controls whether inconsistent-quotes generates a warning when the -# character used as a quote delimiter is used inconsistently within a module. -check-quote-consistency=no - -# This flag controls whether the implicit-str-concat should generate a warning -# on implicit string concatenation in sequences defined over several lines. -check-str-concat-over-line-jumps=no - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether to warn about missing members when the owner of the attribute -# is inferred to be None. -ignore-none=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of symbolic message names to ignore for Mixin members. -ignored-checks-for-mixins=no-member, - not-async-context-manager, - not-context-manager, - attribute-defined-outside-init - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - -# Regex pattern to define which classes are considered mixins. -mixin-class-rgx=.*[Mm]ixin - -# List of decorators that change the signature of a decorated function. -signature-mutators= - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid defining new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of names allowed to shadow builtins -allowed-redefined-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_, - _cb - -# A regular expression matching the name of dummy variables (i.e. expected to -# not be used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io diff --git a/python/remotivelabs-broker/.ruff.toml b/python/remotivelabs-broker/.ruff.toml deleted file mode 100644 index 8b1d4fc..0000000 --- a/python/remotivelabs-broker/.ruff.toml +++ /dev/null @@ -1,76 +0,0 @@ -# Exclude a variety of commonly ignored directories. -exclude = [ - ".bzr", - ".direnv", - ".eggs", - ".git", - ".git-rewrite", - ".hg", - ".ipynb_checkpoints", - ".mypy_cache", - ".nox", - ".pants.d", - ".pyenv", - ".pytest_cache", - ".pytype", - ".ruff_cache", - ".svn", - ".tox", - ".venv", - ".vscode", - "__pypackages__", - "_build", - "buck-out", - "build", - "dist", - "node_modules", - "site-packages", - "venv", - 'deps', - 'binaries', - '__pycache__' -] - -line-length = 140 -indent-width = 4 - -# Assume Python 3.8 -target-version = "py38" - -[lint] -select = ["C901", "E", "W", "F", "RET505", "I001", "B034", "EXE001", "N806", "UP032", "FA100"] -ignore = [] - -# Allow fix for all enabled rules (when `--fix`) is provided. -fixable = ["ALL"] -unfixable = [] - -# Allow unused variables when underscore-prefixed. -dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" - -[format] -# Like Black, use double quotes for strings. -quote-style = "double" - -# Like Black, indent with spaces, rather than tabs. -indent-style = "space" - -# Like Black, respect magic trailing commas. -skip-magic-trailing-comma = false - -# Like Black, automatically detect the appropriate line ending. -line-ending = "auto" - -# Enable auto-formatting of code examples in docstrings. Markdown, -# reStructuredText code/literal blocks and doctests are all supported. -# -# This is currently disabled by default, but it is planned for this -# to be opt-out in the future. -docstring-code-format = false - -# Set the line length limit used when formatting code snippets in -# docstrings. -# -# This only has an effect when the `docstring-code-format` setting is -# enabled. -docstring-code-line-length = "dynamic" diff --git a/python/remotivelabs-broker/README.md b/python/remotivelabs-broker/README.md index a1c561a..a58cd72 100644 --- a/python/remotivelabs-broker/README.md +++ b/python/remotivelabs-broker/README.md @@ -1,62 +1,27 @@ -# RemotiveLabs Broker +# RemotiveLabs Broker API [![PyPI - Version](https://img.shields.io/pypi/v/remotivelabs-broker.svg)](https://pypi.org/project/remotivelabs-broker) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/remotivelabs-broker.svg)](https://pypi.org/project/remotivelabs-broker) -- [Link to **Samples**](https://github.com/remotivelabs/remotivelabs-samples/tree/main/python). -- [Link to **Documentation**](https://docs.remotivelabs.com/apis/python/remotivelabs/broker). - ------ - -**Table of Contents** - -- [Installation](#installation) -- [Examples](#examples) -- [Build and Publish](#build-and-publish) -- [License](#license) +`remotivelabs-broker` is a simple library for interfacing with the [RemotiveBroker](https://docs.remotivelabs.com/docs/remotive-broker). ## Installation + Install into your Python environment with _PIP_: - pip install remotivelabs-broker +```bash +pip install remotivelabs-broker +``` ## Examples -Examples using this library are found in the [Remotive Labs samples repository](https://github.com/remotivelabs/remotivelabs-samples). - - -### Develop and test locally - -Put version in `__about__.py`. Beta versions should be suffixed with `b*`, example `0.2.0b1` - -For initial build and generation of proto stubs, documentation and distribution package, run `./docker-build.sh` - - -Once stubs are generated you can use hatch to build distribution package - hatch build +See [examples](./examples/README.md) -above command will output - - [wheel] - dist/remotivelabs_broker-0.2.0b12-py3-none-any.whl - -You can now install this library version in another terminal by doing +## License - pip3 install [your path]/dist/remotivelabs_broker-0.2.0b12-py3-none-any.whl +`remotivelabs-broker` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license. -### Build and publish -Make sure to put version in `__about__.py`. Beta versions should be suffixed with `b*`, example `0.2.0b1` +## Documentation -``` -./docker-build.sh -hatch publish -``` -find username and password in less secret location -or use -``` -hatch publish --user __token__ -``` -## License - -`remotivelabs-broker` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license. +See [https://docs.remotivelabs.com/apis/python/remotivelabs/broker](https://docs.remotivelabs.com/apis/python/remotivelabs/broker). diff --git a/python/remotivelabs-broker/docker-build.sh b/python/remotivelabs-broker/docker-build.sh index a4fbb18..3776ca3 100755 --- a/python/remotivelabs-broker/docker-build.sh +++ b/python/remotivelabs-broker/docker-build.sh @@ -1,21 +1,16 @@ #!/bin/bash - +# +# Generates code from proto files, builds package and generates documentation +# set -e -# Generates code from proto files, builds package and generates documentation +SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" && pwd) +TAG=remotivelabs/python-api-build-image -docker build -t remotivelabs/python-api-build-image -f docker/Dockerfile . +docker build -t "${TAG}" -f "${SCRIPT_DIR}/docker/Dockerfile" "${SCRIPT_DIR}" +# set args to allow build to run in non-tty shells ARGS="-it" +[ "${NO_TTY}" == "true" ] && ARGS="-i" -if [ "${NO_TTY}" == "true" ]; then - ARGS="-i" -fi - - -docker run \ - -u $(id -u):$(id -g) \ - -v $(pwd)/../../:/app \ - -e "protofile=*.proto" \ - -w /app \ - ${ARGS} remotivelabs/python-api-build-image +docker run -v "${SCRIPT_DIR}/../../:/app" "${ARGS}" "${TAG}" diff --git a/python/remotivelabs-broker/docker/Dockerfile b/python/remotivelabs-broker/docker/Dockerfile index 6abb261..3aaf57a 100644 --- a/python/remotivelabs-broker/docker/Dockerfile +++ b/python/remotivelabs-broker/docker/Dockerfile @@ -1,28 +1,42 @@ -# Make sure we are on same or lower version of protoc than we -# This Dockerfile ensures that we are using libprotoc 3.19.2 -# but this is is determined by the version of grpcio-tools +FROM python:3.10-slim -FROM ubuntu:jammy +ENV protofile=*.proto \ + # python config + PYTHONFAULTHANDLER=1 \ + PYTHONUNBUFFERED=1 \ + PYTHONHASHSEED=random \ + # pip config + PIP_NO_CACHE_DIR=off \ + PIP_DISABLE_PIP_VERSION_CHECK=on \ + PIP_DEFAULT_TIMEOUT=100 \ + # poetry config + POETRY_VERSION=1.8 \ + POETRY_VIRTUALENVS_IN_PROJECT=false +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + wget \ + unzip && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* -ARG URL_PROTOC_DOC=https://github.com/pseudomuto/protoc-gen-doc/releases/download/v1.5.1/protoc-gen-doc_1.5.1_linux_amd64.tar.gz -RUN apt-get update && apt-get install -y python3.11 python3-pip wget unzip -RUN pip install hatch json-schema-for-humans -RUN pip3 install grpcio-tools==1.44.0 -RUN pip3 install hatch -RUN pip3 install pdoc -RUN pip3 install mypy-protobuf==3.3.0 -COPY docker/download_protoc.sh . -RUN rm /bin/sh && ln -s /bin/bash /bin/sh -RUN sh download_protoc.sh +# See https://python-poetry.org/docs/#ci-recommendations +RUN pip install "poetry==$POETRY_VERSION" +RUN poetry self add 'poethepoet[poetry_plugin]' +# install the protobuf compiler +COPY --chmod=0755 docker/download_protoc.sh /tmp/download_protoc.sh +RUN /tmp/download_protoc.sh -RUN wget ${URL_PROTOC_DOC} -O /tmp/protoc.tar.gz && \ - tar zxfv /tmp/protoc.tar.gz protoc-gen-doc && \ - mv protoc-gen-doc /usr/bin -v +# ... and the documentation plugin for protobuf compiler +COPY --chmod=0755 docker/download_protoc_gen_doc.sh /tmp/download_protoc_gen_doc.sh +RUN /tmp/download_protoc_gen_doc.sh + +# Set up build script and entrypoint. It is possible to customize arguments to it using CMD or from command line +COPY --chmod=755 docker/entrypoint.sh /usr/local/bin/entrypoint.sh +COPY --chmod=755 docker/build.sh /usr/local/bin/build.sh VOLUME /app -ENV protofile=*.proto -VOLUME /ouput +WORKDIR /app -CMD ["./python/remotivelabs-broker/docker/build-all-in-docker.sh"] +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/python/remotivelabs-broker/docker/build-all-in-docker.sh b/python/remotivelabs-broker/docker/build-all-in-docker.sh deleted file mode 100755 index d843cb1..0000000 --- a/python/remotivelabs-broker/docker/build-all-in-docker.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash - -set -e - -HOME=/app/python/remotivelabs-broker -STUBS_OUTPUT=$HOME/remotivelabs/broker/generated/sync -mkdir -p "${STUBS_OUTPUT}" - -#1.1 Generate stubs -python3 -m grpc_tools.protoc \ - -I /app/protos \ - --python_out=$STUBS_OUTPUT \ - --grpc_python_out=$STUBS_OUTPUT \ - --mypy_out=$STUBS_OUTPUT \ - --mypy_grpc_out=$STUBS_OUTPUT \ - /app/protos/*.proto - -cd $HOME -#1.2 Fix those imports -python3 misc/fix_import_statements.py - -rm -rf dist - -# Build distribution wheel -hatch build - -# Install wheel in order for pdoc to run properly so docs can be built -dist_wheel=$(ls -AU dist/*.whl | head -1) -echo "dist = $dist_wheel" -pip3 install $dist_wheel - - -# Build python documentation - -mkdir -p dist/doc/ -DOCS=$(realpath dist/doc) - - -function generate_python_docs() { - PY_DOCS=$DOCS/python - mkdir $PY_DOCS - - pdoc \ - --favicon https://releases.remotivelabs.com/favicon.ico \ - --logo https://releases.remotivelabs.com/remotive-labs-logo-neg.png \ - --no-show-source \ - -t misc/theme \ - -o $PY_DOCS \ - ./remotivelabs -} - -function generate_proto_docs() { - PROTO_DOCS=$DOCS/protos - mkdir $PROTO_DOCS - PROTO_FILES="common.proto network_api.proto system_api.proto traffic_api.proto" - protoc --doc_out=$PROTO_DOCS --doc_opt=html,index.html $PROTO_FILES -} - -function generate_json() { - JSON_DOCS=$DOCS/json - mkdir $JSON_DOCS - # Generate - generate-schema-doc metadb.json $JSON_DOCS - generate-schema-doc interfaces_schema.json $JSON_DOCS - generate-schema-doc scripted_db.json $JSON_DOCS -} - -generate_python_docs -(cd /app/protos && generate_proto_docs) -(cd /app/schemas/ && generate_json) diff --git a/python/remotivelabs-broker/docker/build.sh b/python/remotivelabs-broker/docker/build.sh new file mode 100755 index 0000000..3454ba5 --- /dev/null +++ b/python/remotivelabs-broker/docker/build.sh @@ -0,0 +1,111 @@ +#!/bin/bash +# +# Build the remotivelabs-broker python library together with its documentation. +# +# We use grpc-tools to generate the python stubs for the protobuf definition in protos/ dir, +# and then package the python library using hatch. Documentation is generated for python, protobuf +# and json-schema. +# +set -e + +PROJECT_DIR=/app/python/remotivelabs-broker + +PROTO_IN=/app/protos +PROTO_STUBS_OUT=$PROJECT_DIR/remotivelabs/broker/generated/sync + +SCHEMA_IN=/app/schemas + +BUILD_DIR=$PROJECT_DIR/dist + +DOCS_DIR=$PROJECT_DIR/dist/doc +PY_DOCS=$DOCS_DIR/python +PROTO_DOCS=$DOCS_DIR/protos +JSON_DOCS=$DOCS_DIR/json + +function setup_build_env() { + cd $PROJECT_DIR + rm -rf $BUILD_DIR + + # Make sure we dont mess up any .venv already present in the mounted volume + export POETRY_VIRTUALENVS_IN_PROJECT=false + poetry install +} + +function generate_protobuf_files() { + mkdir -p "${PROTO_STUBS_OUT}" + + poetry run python -m grpc_tools.protoc \ + --proto_path=$PROTO_IN \ + --python_out=$PROTO_STUBS_OUT \ + --grpc_python_out=$PROTO_STUBS_OUT \ + --pyi_out=$PROTO_STUBS_OUT \ + $PROTO_IN/*.proto + + # Note: protobuf compiler does not support generating relative or custom absolute imports for python. Use a script to do this manually... + poetry run python $PROJECT_DIR/misc/fix_import_statements.py +} + +function build_python_library() { + poetry build +} + +function generate_python_docs() { + mkdir -p $PY_DOCS + + poetry run pdoc \ + --favicon https://releases.remotivelabs.com/favicon.ico \ + --logo https://releases.remotivelabs.com/remotive-labs-logo-neg.png \ + --no-show-source \ + -t misc/theme \ + -o $PY_DOCS \ + $PROJECT_DIR/remotivelabs +} + +# TODO: Move away from python lib +# TODO: Investigate the possibility to use grpcio-tools proto compiler instead of this custom one. +# See e.g. protoc-docs-plugin on pypi +function generate_proto_docs() { + mkdir -p $PROTO_DOCS + + PROTO_FILES="$PROTO_IN/common.proto $PROTO_IN/network_api.proto $PROTO_IN/system_api.proto $PROTO_IN/traffic_api.proto" + protoc -I $PROTO_IN --doc_out=$PROTO_DOCS --doc_opt=html,index.html $PROTO_FILES +} + +# TODO: Move away from python lib +function generate_json() { + mkdir -p $JSON_DOCS + + poetry run generate-schema-doc $SCHEMA_IN/metadb.json $JSON_DOCS + poetry run generate-schema-doc $SCHEMA_IN/interfaces_schema.json $JSON_DOCS + poetry run generate-schema-doc $SCHEMA_IN/scripted_db.json $JSON_DOCS +} + +echo -e "\n######################" +echo "Installing python dependencies in ${PROJECT_DIR}" +echo "######################" +setup_build_env + +echo -e "\n######################" +echo "Generating protobuf files to ${PROTO_STUBS_OUT}" +echo "######################" +generate_protobuf_files + +echo -e "\n######################" +echo "Building python library in ${BUILD_DIR}" +echo "######################" +build_python_library + +echo -e "\n######################" +echo "Generating pydocs in ${PY_DOCS}" +echo "######################" +generate_python_docs + +echo -e "\n######################" +echo "Generating protobuf docs to ${PROTO_DOCS}" +echo "######################" +generate_proto_docs + +echo -e "\n######################" +echo "Generating json schema docs to ${JSON_DOCS}" +echo "######################" +generate_json diff --git a/python/remotivelabs-broker/docker/download_protoc.sh b/python/remotivelabs-broker/docker/download_protoc.sh index cc3cc33..376830f 100644 --- a/python/remotivelabs-broker/docker/download_protoc.sh +++ b/python/remotivelabs-broker/docker/download_protoc.sh @@ -1,14 +1,41 @@ -#!/bin/sh - +#!/bin/bash # # Downloads correct protoc compiler for correct platform during docker build # +PROTOC_VERSION="28.2" +BASE_URL="https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}" + +ARCH=$(uname -m) +OS=$(uname -s) + +case "${OS}-${ARCH}" in + "Linux-x86_64") + URL="${BASE_URL}-linux-x86_64.zip" + ;; + "Linux-aarch64") + URL="${BASE_URL}-linux-aarch_64.zip" + ;; + "Darwin-arm64") + URL="${BASE_URL}-osx-aarch_64.zip" + ;; + *) + echo "Unsupported platform: ${OS}-${ARCH}" + exit 1 + ;; +esac + +# Create a temporary directory and set up cleanup +TMP_DIR=$(mktemp -d) +cleanup() { + rm -rf "$TMP_DIR" +} +trap cleanup EXIT -mkdir /apps -mkdir /app -export ARCH=$(uname -p) +echo "Downloading protoc compiler for ${OS}-${ARCH} from: $URL" +wget "$URL" -O "$TMP_DIR/proto-compiler.zip" -if [ "$ARCH" = "aarch64" ] ; then export ARCH=aarch_64 ; else export ARCH=x86_64 ; fi +unzip "$TMP_DIR/proto-compiler.zip" -d "$TMP_DIR" +mv "$TMP_DIR/bin/protoc" /usr/bin/protoc +chmod +x /usr/bin/protoc -(wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.2/protoc-3.19.2-linux-$ARCH.zip -O /tmp/proto-compiler.zip && -cd tmp && unzip proto-compiler.zip && mv /tmp/bin/protoc /bin/protoc && chmod 777 /bin/protoc) \ No newline at end of file +echo "protoc compiler installed successfully!" diff --git a/python/remotivelabs-broker/docker/download_protoc_gen_doc.sh b/python/remotivelabs-broker/docker/download_protoc_gen_doc.sh new file mode 100644 index 0000000..7d3e3ab --- /dev/null +++ b/python/remotivelabs-broker/docker/download_protoc_gen_doc.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Downloads the correct documentation generator plugin for the Google Protocol Buffers compiler +# +PROTOC_GEN_DOC_VERSION="1.5.1" +BASE_URL="https://github.com/pseudomuto/protoc-gen-doc/releases/download/v${PROTOC_GEN_DOC_VERSION}/protoc-gen-doc_${PROTOC_GEN_DOC_VERSION}" + +ARCH=$(uname -m) +OS=$(uname -s) + +case "${OS}-${ARCH}" in + "Linux-x86_64") + URL="${BASE_URL}_linux_amd64.tar.gz" + ;; + "Linux-aarch64") + URL="${BASE_URL}_linux_arm64.tar.gz" + ;; + "Darwin-arm64") + URL="${BASE_URL}_darwin_arm64.tar.gz" + ;; + *) + echo "Unsupported platform: ${OS}-${ARCH}" + exit 1 + ;; +esac + +# Create a temporary directory and set up cleanup +TMP_DIR=$(mktemp -d) +cleanup() { + rm -rf "$TMP_DIR" +} +trap cleanup EXIT + +echo "Downloading protoc-gen-doc for ${OS}-${ARCH} from: $URL" +wget "$URL" -O "$TMP_DIR/protoc-gen-doc.tar.gz" + +tar -zxf "$TMP_DIR/protoc-gen-doc.tar.gz" -C "$TMP_DIR" +mv "$TMP_DIR/protoc-gen-doc" /usr/bin/protoc-gen-doc +chmod +x /usr/bin/protoc-gen-doc + +echo "protoc compiler documentation plugin installed successfully!" diff --git a/python/remotivelabs-broker/docker/entrypoint.sh b/python/remotivelabs-broker/docker/entrypoint.sh new file mode 100755 index 0000000..276f64e --- /dev/null +++ b/python/remotivelabs-broker/docker/entrypoint.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# +# Docker entrypoint +# +# Creates a dummy user (hostuser) with the same UID/GID as the host user and executes the build script (build.sh) with that user. +# This has several benefits, including: +# - hostuser has its own HOME directory, which it has full permissions to. +# - hostuser will have full access to the mounted host directory. +# - hostuser will produce output files with the correct permissions for host to access them later. +# - you may pass on environment variables to hostuser by appending them to /home/hostuser/.bashrc +# +set -e + +create_group_if_not_exists() { + local gid=$1 + if ! getent group "$gid" >/dev/null 2>&1; then + addgroup --gid "$gid" hostgroup --quiet + fi +} + +create_user_if_not_exists() { + local uid=$1 + local gid=$2 + if ! getent passwd "$uid" >/dev/null 2>&1; then + adduser --uid "$uid" --gid "$gid" --disabled-password --gecos "" hostuser --quiet + fi +} + +# We know that working dir is set to the mounted host volume. Get the UID/GID of the owner so that we can run as that user in the container. +HOST_UID=$(stat -c "%u" "$PWD") +HOST_GID=$(stat -c "%g" "$PWD") + +CURRENT_UID=$(id -u) +CURRENT_GID=$(id -g) + +create_group_if_not_exists "$HOST_GID" +create_user_if_not_exists "$HOST_UID" "$HOST_GID" + +if [ "$CURRENT_UID" -eq "$HOST_UID" ] && [ "$CURRENT_GID" -eq "$HOST_GID" ]; then + exec /usr/local/bin/build.sh "$@" +else + user=$(getent passwd "$HOST_UID" | cut -d: -f1) + exec su - "$user" -c "/usr/local/bin/build.sh $@" +fi diff --git a/python/remotivelabs-broker/misc/fix_import_statements.py b/python/remotivelabs-broker/misc/fix_import_statements.py index dd55b7a..2eee14f 100644 --- a/python/remotivelabs-broker/misc/fix_import_statements.py +++ b/python/remotivelabs-broker/misc/fix_import_statements.py @@ -7,6 +7,11 @@ # # This script goes through all the python files in the folder and does the replacement based on the regex pattern # `regex_string` defined below. +# +# See also: +# - https://github.com/grpc/grpc/issues/9575 +# - https://github.com/protocolbuffers/protobuf/issues/1491 +# - https://github.com/protocolbuffers/protobuf/issues/5374 import glob import re diff --git a/python/remotivelabs-broker/poetry.lock b/python/remotivelabs-broker/poetry.lock new file mode 100644 index 0000000..7800bed --- /dev/null +++ b/python/remotivelabs-broker/poetry.lock @@ -0,0 +1,1172 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "astroid" +version = "3.2.4" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "astroid-3.2.4-py3-none-any.whl", hash = "sha256:413658a61eeca6202a59231abb473f932038fbcbf1666587f66d482083413a25"}, + {file = "astroid-3.2.4.tar.gz", hash = "sha256:0e14202810b30da1b735827f78f5157be2bbd4a7a59b7707ca0bfc2fb4c0063a"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "astunparse" +version = "1.6.3" +description = "An AST unparser for Python" +optional = false +python-versions = "*" +files = [ + {file = "astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"}, + {file = "astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872"}, +] + +[package.dependencies] +six = ">=1.6.1,<2.0" +wheel = ">=0.23.0,<1.0" + +[[package]] +name = "certifi" +version = "2024.8.30" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.6.1" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "dataclasses-json" +version = "0.5.9" +description = "Easily serialize dataclasses to and from JSON" +optional = false +python-versions = ">=3.6" +files = [ + {file = "dataclasses-json-0.5.9.tar.gz", hash = "sha256:e9ac87b73edc0141aafbce02b44e93553c3123ad574958f0fe52a534b6707e8e"}, + {file = "dataclasses_json-0.5.9-py3-none-any.whl", hash = "sha256:1280542631df1c375b7bc92e5b86d39e06c44760d7e3571a537b3b8acabf2f0c"}, +] + +[package.dependencies] +marshmallow = ">=3.3.0,<4.0.0" +marshmallow-enum = ">=1.5.1,<2.0.0" +typing-inspect = ">=0.4.0" + +[package.extras] +dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=7.2.0)", "setuptools", "simplejson", "twine", "types-dataclasses", "wheel"] + +[[package]] +name = "dill" +version = "0.3.9" +description = "serialize all of Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, + {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "grpc-interceptor" +version = "0.15.4" +description = "Simplifies gRPC interceptors" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "grpc-interceptor-0.15.4.tar.gz", hash = "sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926"}, + {file = "grpc_interceptor-0.15.4-py3-none-any.whl", hash = "sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d"}, +] + +[package.dependencies] +grpcio = ">=1.49.1,<2.0.0" + +[package.extras] +testing = ["protobuf (>=4.21.9)"] + +[[package]] +name = "grpc-stubs" +version = "1.53.0.5" +description = "Mypy stubs for gRPC" +optional = false +python-versions = ">=3.6" +files = [ + {file = "grpc-stubs-1.53.0.5.tar.gz", hash = "sha256:3e1b642775cbc3e0c6332cfcedfccb022176db87e518757bef3a1241397be406"}, + {file = "grpc_stubs-1.53.0.5-py3-none-any.whl", hash = "sha256:04183fb65a1b166a1febb9627e3d9647d3926ccc2dfe049fe7b6af243428dbe1"}, +] + +[package.dependencies] +grpcio = "*" + +[[package]] +name = "grpcio" +version = "1.66.2" +description = "HTTP/2-based RPC framework" +optional = false +python-versions = ">=3.8" +files = [ + {file = "grpcio-1.66.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:fe96281713168a3270878255983d2cb1a97e034325c8c2c25169a69289d3ecfa"}, + {file = "grpcio-1.66.2-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:73fc8f8b9b5c4a03e802b3cd0c18b2b06b410d3c1dcbef989fdeb943bd44aff7"}, + {file = "grpcio-1.66.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:03b0b307ba26fae695e067b94cbb014e27390f8bc5ac7a3a39b7723fed085604"}, + {file = "grpcio-1.66.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d69ce1f324dc2d71e40c9261d3fdbe7d4c9d60f332069ff9b2a4d8a257c7b2b"}, + {file = "grpcio-1.66.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05bc2ceadc2529ab0b227b1310d249d95d9001cd106aa4d31e8871ad3c428d73"}, + {file = "grpcio-1.66.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ac475e8da31484efa25abb774674d837b343afb78bb3bcdef10f81a93e3d6bf"}, + {file = "grpcio-1.66.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0be4e0490c28da5377283861bed2941d1d20ec017ca397a5df4394d1c31a9b50"}, + {file = "grpcio-1.66.2-cp310-cp310-win32.whl", hash = "sha256:4e504572433f4e72b12394977679161d495c4c9581ba34a88d843eaf0f2fbd39"}, + {file = "grpcio-1.66.2-cp310-cp310-win_amd64.whl", hash = "sha256:2018b053aa15782db2541ca01a7edb56a0bf18c77efed975392583725974b249"}, + {file = "grpcio-1.66.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:2335c58560a9e92ac58ff2bc5649952f9b37d0735608242973c7a8b94a6437d8"}, + {file = "grpcio-1.66.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45a3d462826f4868b442a6b8fdbe8b87b45eb4f5b5308168c156b21eca43f61c"}, + {file = "grpcio-1.66.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:a9539f01cb04950fd4b5ab458e64a15f84c2acc273670072abe49a3f29bbad54"}, + {file = "grpcio-1.66.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce89f5876662f146d4c1f695dda29d4433a5d01c8681fbd2539afff535da14d4"}, + {file = "grpcio-1.66.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25a14af966438cddf498b2e338f88d1c9706f3493b1d73b93f695c99c5f0e2a"}, + {file = "grpcio-1.66.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6001e575b8bbd89eee11960bb640b6da6ae110cf08113a075f1e2051cc596cae"}, + {file = "grpcio-1.66.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4ea1d062c9230278793820146c95d038dc0f468cbdd172eec3363e42ff1c7d01"}, + {file = "grpcio-1.66.2-cp311-cp311-win32.whl", hash = "sha256:38b68498ff579a3b1ee8f93a05eb48dc2595795f2f62716e797dc24774c1aaa8"}, + {file = "grpcio-1.66.2-cp311-cp311-win_amd64.whl", hash = "sha256:6851de821249340bdb100df5eacfecfc4e6075fa85c6df7ee0eb213170ec8e5d"}, + {file = "grpcio-1.66.2-cp312-cp312-linux_armv7l.whl", hash = "sha256:802d84fd3d50614170649853d121baaaa305de7b65b3e01759247e768d691ddf"}, + {file = "grpcio-1.66.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:80fd702ba7e432994df208f27514280b4b5c6843e12a48759c9255679ad38db8"}, + {file = "grpcio-1.66.2-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:12fda97ffae55e6526825daf25ad0fa37483685952b5d0f910d6405c87e3adb6"}, + {file = "grpcio-1.66.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:950da58d7d80abd0ea68757769c9db0a95b31163e53e5bb60438d263f4bed7b7"}, + {file = "grpcio-1.66.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e636ce23273683b00410f1971d209bf3689238cf5538d960adc3cdfe80dd0dbd"}, + {file = "grpcio-1.66.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a917d26e0fe980b0ac7bfcc1a3c4ad6a9a4612c911d33efb55ed7833c749b0ee"}, + {file = "grpcio-1.66.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49f0ca7ae850f59f828a723a9064cadbed90f1ece179d375966546499b8a2c9c"}, + {file = "grpcio-1.66.2-cp312-cp312-win32.whl", hash = "sha256:31fd163105464797a72d901a06472860845ac157389e10f12631025b3e4d0453"}, + {file = "grpcio-1.66.2-cp312-cp312-win_amd64.whl", hash = "sha256:ff1f7882e56c40b0d33c4922c15dfa30612f05fb785074a012f7cda74d1c3679"}, + {file = "grpcio-1.66.2-cp313-cp313-linux_armv7l.whl", hash = "sha256:3b00efc473b20d8bf83e0e1ae661b98951ca56111feb9b9611df8efc4fe5d55d"}, + {file = "grpcio-1.66.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1caa38fb22a8578ab8393da99d4b8641e3a80abc8fd52646f1ecc92bcb8dee34"}, + {file = "grpcio-1.66.2-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:c408f5ef75cfffa113cacd8b0c0e3611cbfd47701ca3cdc090594109b9fcbaed"}, + {file = "grpcio-1.66.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c806852deaedee9ce8280fe98955c9103f62912a5b2d5ee7e3eaa284a6d8d8e7"}, + {file = "grpcio-1.66.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f145cc21836c332c67baa6fc81099d1d27e266401565bf481948010d6ea32d46"}, + {file = "grpcio-1.66.2-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:73e3b425c1e155730273f73e419de3074aa5c5e936771ee0e4af0814631fb30a"}, + {file = "grpcio-1.66.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:9c509a4f78114cbc5f0740eb3d7a74985fd2eff022971bc9bc31f8bc93e66a3b"}, + {file = "grpcio-1.66.2-cp313-cp313-win32.whl", hash = "sha256:20657d6b8cfed7db5e11b62ff7dfe2e12064ea78e93f1434d61888834bc86d75"}, + {file = "grpcio-1.66.2-cp313-cp313-win_amd64.whl", hash = "sha256:fb70487c95786e345af5e854ffec8cb8cc781bcc5df7930c4fbb7feaa72e1cdf"}, + {file = "grpcio-1.66.2-cp38-cp38-linux_armv7l.whl", hash = "sha256:a18e20d8321c6400185b4263e27982488cb5cdd62da69147087a76a24ef4e7e3"}, + {file = "grpcio-1.66.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:02697eb4a5cbe5a9639f57323b4c37bcb3ab2d48cec5da3dc2f13334d72790dd"}, + {file = "grpcio-1.66.2-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:99a641995a6bc4287a6315989ee591ff58507aa1cbe4c2e70d88411c4dcc0839"}, + {file = "grpcio-1.66.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ed71e81782966ffead60268bbda31ea3f725ebf8aa73634d5dda44f2cf3fb9c"}, + {file = "grpcio-1.66.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbd27c24a4cc5e195a7f56cfd9312e366d5d61b86e36d46bbe538457ea6eb8dd"}, + {file = "grpcio-1.66.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d9a9724a156c8ec6a379869b23ba3323b7ea3600851c91489b871e375f710bc8"}, + {file = "grpcio-1.66.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d8d4732cc5052e92cea2f78b233c2e2a52998ac40cd651f40e398893ad0d06ec"}, + {file = "grpcio-1.66.2-cp38-cp38-win32.whl", hash = "sha256:7b2c86457145ce14c38e5bf6bdc19ef88e66c5fee2c3d83285c5aef026ba93b3"}, + {file = "grpcio-1.66.2-cp38-cp38-win_amd64.whl", hash = "sha256:e88264caad6d8d00e7913996030bac8ad5f26b7411495848cc218bd3a9040b6c"}, + {file = "grpcio-1.66.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:c400ba5675b67025c8a9f48aa846f12a39cf0c44df5cd060e23fda5b30e9359d"}, + {file = "grpcio-1.66.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:66a0cd8ba6512b401d7ed46bb03f4ee455839957f28b8d61e7708056a806ba6a"}, + {file = "grpcio-1.66.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:06de8ec0bd71be123eec15b0e0d457474931c2c407869b6c349bd9bed4adbac3"}, + {file = "grpcio-1.66.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb57870449dfcfac428afbb5a877829fcb0d6db9d9baa1148705739e9083880e"}, + {file = "grpcio-1.66.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b672abf90a964bfde2d0ecbce30f2329a47498ba75ce6f4da35a2f4532b7acbc"}, + {file = "grpcio-1.66.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ad2efdbe90c73b0434cbe64ed372e12414ad03c06262279b104a029d1889d13e"}, + {file = "grpcio-1.66.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9c3a99c519f4638e700e9e3f83952e27e2ea10873eecd7935823dab0c1c9250e"}, + {file = "grpcio-1.66.2-cp39-cp39-win32.whl", hash = "sha256:78fa51ebc2d9242c0fc5db0feecc57a9943303b46664ad89921f5079e2e4ada7"}, + {file = "grpcio-1.66.2-cp39-cp39-win_amd64.whl", hash = "sha256:728bdf36a186e7f51da73be7f8d09457a03061be848718d0edf000e709418987"}, + {file = "grpcio-1.66.2.tar.gz", hash = "sha256:563588c587b75c34b928bc428548e5b00ea38c46972181a4d8b75ba7e3f24231"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.66.2)"] + +[[package]] +name = "grpcio-tools" +version = "1.66.2" +description = "Protobuf code generator for gRPC" +optional = false +python-versions = ">=3.8" +files = [ + {file = "grpcio_tools-1.66.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:40b7ad804ff78490408177cfe87427d5a67224f82a2bdfabe9d8d6ac6239733b"}, + {file = "grpcio_tools-1.66.2-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:a886fa2ff9e897b35489557d1c61cbc0e4efc42c4dc0d120a9516f294fefb107"}, + {file = "grpcio_tools-1.66.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:1d5e22b2c7f5b453462c85aa66f99961d5c7b275d1c60b84fe847c06c73c9400"}, + {file = "grpcio_tools-1.66.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a425b2600ad4fcf887107ee975a9b7c20478c2959c58b12af7f36577d7a7f7b3"}, + {file = "grpcio_tools-1.66.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef979af76b0cd3f5235d3ec30e86a4f0acc0eab179e796ddbb481aa351a1e6ca"}, + {file = "grpcio_tools-1.66.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:99638043e1a78b8617f31b676f1ecf248d75a45b318776af3acc48a85c8e10a2"}, + {file = "grpcio_tools-1.66.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0a465850c7e5c4ab588c7b7275d47781e9c0ee397a8faf4977262592f95e1831"}, + {file = "grpcio_tools-1.66.2-cp310-cp310-win32.whl", hash = "sha256:48997b704d2fcf59d922228c7a79fcd35d52ca8b2202e5cfe193962643b8354f"}, + {file = "grpcio_tools-1.66.2-cp310-cp310-win_amd64.whl", hash = "sha256:ab4eda584ba2e647e9bb5098f5e4e8d370a333761bf33924e9a7c14f069c8b08"}, + {file = "grpcio_tools-1.66.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:007750b4db62018e441f8401fa567aa11174ae0173826cbbe54982fdf2383067"}, + {file = "grpcio_tools-1.66.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:18554bc91640b2f1ce18aa5c6bebd51500ca0b43b5df4e700e6f76522e2b0e94"}, + {file = "grpcio_tools-1.66.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:3fe2fc2e4a16d745cae01e1348b401378e58ced920ff759a6b4b85a7ad507896"}, + {file = "grpcio_tools-1.66.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0933420362621d8792fea9350f0c82c514da5f93888d1476c37d9e3722d260b0"}, + {file = "grpcio_tools-1.66.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3aef5abd34bea8ea98448cd58a938992238c4717df93d12f84fa5f56efb11d0"}, + {file = "grpcio_tools-1.66.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7afd9eb9be413a731cff7ad638081795a7ed0fec4b23af5cec2099fbd9d742f9"}, + {file = "grpcio_tools-1.66.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fd1fa95188ae7d5460a8c4a2abcb2777fdf9c3b80d592a2e8434c52a6eb48e8d"}, + {file = "grpcio_tools-1.66.2-cp311-cp311-win32.whl", hash = "sha256:80c233215cf0f08353b7aac4e86cdedf4d545ed368a7491ccc9996e5a317dce4"}, + {file = "grpcio_tools-1.66.2-cp311-cp311-win_amd64.whl", hash = "sha256:2a9a376b300aa2b4da8e6c4f6f746e824d3f24eefeac2753ffffe2b9f37d156d"}, + {file = "grpcio_tools-1.66.2-cp312-cp312-linux_armv7l.whl", hash = "sha256:d8ca76fc40a7d35ddf1229afd04408e2ff94caf4385068c8b147e064e951e0ba"}, + {file = "grpcio_tools-1.66.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6cc3da6994d575c425c74ce33e34b86a975ea7e78bb9c3525e8439a3af3c508f"}, + {file = "grpcio_tools-1.66.2-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:89e437ced43275e7427cc82a837f5cd43ebe18a1080b0e50a47627895b44b0e6"}, + {file = "grpcio_tools-1.66.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d95f030e708266d7fd6d3e5d56e30a9bbbe230604856b1fe93edd892e4389aab"}, + {file = "grpcio_tools-1.66.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b3cf9ae67f8bb431ab3ff60db75c3586dc5aa993be4b15bd7cad651362563cd"}, + {file = "grpcio_tools-1.66.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:b4896a0853fc402273e908c0a0710d25242f1ae907efb9d22ba6d82d4ba00ad8"}, + {file = "grpcio_tools-1.66.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d31aad10f90fccb0073bc03b4d1b67690ef4f0cd9af96e82944b9cc655d12b6f"}, + {file = "grpcio_tools-1.66.2-cp312-cp312-win32.whl", hash = "sha256:d8f976f35683e49467d0bf2b90c170ac5443cd162d48d8d868801fd0d87a5fa8"}, + {file = "grpcio_tools-1.66.2-cp312-cp312-win_amd64.whl", hash = "sha256:b2c19e5a888a6ee48ba699581a90c04806b2a93f574f37449c359ec17a793669"}, + {file = "grpcio_tools-1.66.2-cp313-cp313-linux_armv7l.whl", hash = "sha256:7e8c9aa91a9e51199048202e3c54491e0a89fb3ac47dde36ff2964fbcee143a3"}, + {file = "grpcio_tools-1.66.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0eaedd3c77824c3762b728c485f91097a58116fa135f3bbc24703621476cd866"}, + {file = "grpcio_tools-1.66.2-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:a14007902fb6565c21815da4177105ec905ef37f0550190c4d1bbeb2928c6560"}, + {file = "grpcio_tools-1.66.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df8f098bb92d192230f3b23df514b139f3549e2a4390d1f0f0d8ff89de458c54"}, + {file = "grpcio_tools-1.66.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c68642829368f4f83929e0df571dbbc99f1f1553555d8f98d0582da9f6743d9e"}, + {file = "grpcio_tools-1.66.2-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:5fd20110d2c7706dfdd95457807acb8c050253be2e272b9f5fb977e87ea44d86"}, + {file = "grpcio_tools-1.66.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:4b16244be4cff92408eb82901b883a70f3dd902fb7c7f66e2a368271be84cde4"}, + {file = "grpcio_tools-1.66.2-cp313-cp313-win32.whl", hash = "sha256:d872ba3bbe9e15b43eeb9310dad5edbf490bb3ab0072a46b3a12fed0234eec23"}, + {file = "grpcio_tools-1.66.2-cp313-cp313-win_amd64.whl", hash = "sha256:a2810921218471aab5c8cd20204d3b1886aa8e13b495e882158bb398982cf18e"}, + {file = "grpcio_tools-1.66.2-cp38-cp38-linux_armv7l.whl", hash = "sha256:538eb263b9969e866619775df341307ece0b09afce091ede8141c5bb4d7d8933"}, + {file = "grpcio_tools-1.66.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9a68c71bb1358f0994fc7d0f0d70a0d419d57507faa25c982145be401f6aca48"}, + {file = "grpcio_tools-1.66.2-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:1bc41d5b36d414bb0940aa50e30d624903a2538f9387ae730953675adcbe1498"}, + {file = "grpcio_tools-1.66.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c43dcd3ee13418545ea10416f46296ddbc7fb355cf136ddebd3b3f881a383168"}, + {file = "grpcio_tools-1.66.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc16f9e6baafed315846e79a746513863e6ecbb89e9c98d872834e44f9e87a5"}, + {file = "grpcio_tools-1.66.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3655c96eef8aac2a610bbf4cb9c7839fcff09f07a609b74408b3b0a136e1ef57"}, + {file = "grpcio_tools-1.66.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:86d971fc64e63642058ac01ce2e484a8340d60a95ead0dc6697ef2aa18a7b936"}, + {file = "grpcio_tools-1.66.2-cp38-cp38-win32.whl", hash = "sha256:c14db004b28ee2adefc6d36107d7fdf770f7509bd1f1ecd195eecb88cdbe5d96"}, + {file = "grpcio_tools-1.66.2-cp38-cp38-win_amd64.whl", hash = "sha256:c65f12474634195ff5ed91b304412b80008c067d28226c26b4e451ea9da16b24"}, + {file = "grpcio_tools-1.66.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:75c6a25a5cf729c4606c388013cf7c59dda99cf3718c24fe4fd52b06c19955d0"}, + {file = "grpcio_tools-1.66.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5a5146e780ed87348d84b11fc3843741e676b2a84d493363bf0b4ae31c56841b"}, + {file = "grpcio_tools-1.66.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:c42ba1b24e701544bf08a43bb2d63d56dedd0fd33a5b499c9cf85e15aa154b13"}, + {file = "grpcio_tools-1.66.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5daf9807260e172ffcc5dd582c01f60bac820f99f0151a507c8a537f9e6dceb8"}, + {file = "grpcio_tools-1.66.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a15a4d0f4eba3773dabe07113b42e018a8fa9a28441483ada111991d5c1468b6"}, + {file = "grpcio_tools-1.66.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:cc4f65cd189832676dca16046a4b6247d0bc1fc20648d16ac7fb0b075d1658f4"}, + {file = "grpcio_tools-1.66.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ba63dbcbb8ade67e5a04dd3a6c5860efb454bda6d5e8558b17c9a7251339ce36"}, + {file = "grpcio_tools-1.66.2-cp39-cp39-win32.whl", hash = "sha256:c4df0f547f4193dfa6689949b374974f08d81f129174738f0410ba8d45dc63be"}, + {file = "grpcio_tools-1.66.2-cp39-cp39-win_amd64.whl", hash = "sha256:0cad9ffe5df7801201773b91f14923cf3e20ca764e418ae7f8cb75f6045a0aa1"}, + {file = "grpcio_tools-1.66.2.tar.gz", hash = "sha256:4a36e07913d26ba5ccfd2685ba63ca97f26b08c249d2cc9e74dda37efa49d7e4"}, +] + +[package.dependencies] +grpcio = ">=1.66.2" +protobuf = ">=5.26.1,<6.0dev" +setuptools = "*" + +[[package]] +name = "htmlmin" +version = "0.1.12" +description = "An HTML Minifier" +optional = false +python-versions = "*" +files = [ + {file = "htmlmin-0.1.12.tar.gz", hash = "sha256:50c1ef4630374a5d723900096a961cff426dff46b48f34d194a81bbe14eca178"}, +] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +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.13.2" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[package.extras] +colors = ["colorama (>=0.4.6)"] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "json-schema-for-humans" +version = "1.0.2" +description = "Generate static HTML documentation from JSON schemas" +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "json_schema_for_humans-1.0.2-py3-none-any.whl", hash = "sha256:d6ecb023b4f802b10b01abca1295a37e363d9f060e54c21aa2cddea44731c6e1"}, + {file = "json_schema_for_humans-1.0.2.tar.gz", hash = "sha256:8bd807a2bac31650226e451ad3b9583c27ce916375d6938ac9d0251eb6549ad5"}, +] + +[package.dependencies] +click = ">=8.0.1,<9.0.0" +dataclasses-json = ">=0.5.6,<0.6.0" +htmlmin = ">=0.1.12,<0.2.0" +Jinja2 = ">3" +markdown2 = ">=2.4.1,<3.0.0" +MarkupSafe = ">=2.0,<3.0" +Pygments = ">=2.10.0,<3.0.0" +pytz = "*" +PyYAML = ">=5.4.1,<7" +requests = ">=2.31.0,<3.0.0" + +[[package]] +name = "markdown2" +version = "2.5.1" +description = "A fast and complete Python implementation of Markdown" +optional = false +python-versions = "<4,>=3.8" +files = [ + {file = "markdown2-2.5.1-py2.py3-none-any.whl", hash = "sha256:190ae60a4bd0425c60c863bede18a9f3d45b1cbf3fbc9f40b4fac336ff2c520b"}, + {file = "markdown2-2.5.1.tar.gz", hash = "sha256:12fc04ea5a87f7bb4b65acf5bf3af1183b20838cc7d543b74c92ec7eea4bbc74"}, +] + +[package.extras] +all = ["latex2mathml", "pygments (>=2.7.3)", "wavedrom"] +code-syntax-highlighting = ["pygments (>=2.7.3)"] +latex = ["latex2mathml"] +wavedrom = ["wavedrom"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "marshmallow" +version = "3.22.0" +description = "A lightweight library for converting complex datatypes to and from native Python datatypes." +optional = false +python-versions = ">=3.8" +files = [ + {file = "marshmallow-3.22.0-py3-none-any.whl", hash = "sha256:71a2dce49ef901c3f97ed296ae5051135fd3febd2bf43afe0ae9a82143a494d9"}, + {file = "marshmallow-3.22.0.tar.gz", hash = "sha256:4972f529104a220bb8637d595aa4c9762afbe7f7a77d82dc58c1615d70c5823e"}, +] + +[package.dependencies] +packaging = ">=17.0" + +[package.extras] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] +docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.13)", "sphinx (==8.0.2)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] +tests = ["pytest", "pytz", "simplejson"] + +[[package]] +name = "marshmallow-enum" +version = "1.5.1" +description = "Enum field for Marshmallow" +optional = false +python-versions = "*" +files = [ + {file = "marshmallow-enum-1.5.1.tar.gz", hash = "sha256:38e697e11f45a8e64b4a1e664000897c659b60aa57bfa18d44e226a9920b6e58"}, + {file = "marshmallow_enum-1.5.1-py2.py3-none-any.whl", hash = "sha256:57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072"}, +] + +[package.dependencies] +marshmallow = ">=2.0.0" + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy" +version = "1.11.2" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"}, + {file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"}, + {file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"}, + {file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"}, + {file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"}, + {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, + {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, + {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, + {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, + {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, + {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, + {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, + {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, + {file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"}, + {file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"}, + {file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"}, + {file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"}, + {file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"}, + {file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"}, + {file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"}, + {file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"}, + {file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"}, + {file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"}, + {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, + {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "pdoc" +version = "12.3.1" +description = "API Documentation for Python Projects" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pdoc-12.3.1-py3-none-any.whl", hash = "sha256:c3f24f31286e634de9c76fa6e67bd5c0c5e74360b41dc91e6b82499831eb52d8"}, + {file = "pdoc-12.3.1.tar.gz", hash = "sha256:453236f225feddb8a9071428f1982a78d74b9b3da4bc4433aedb64dbd0cc87ab"}, +] + +[package.dependencies] +astunparse = {version = "*", markers = "python_version < \"3.9\""} +Jinja2 = ">=2.11.0" +MarkupSafe = "*" +pygments = ">=2.12.0" + +[package.extras] +dev = ["black", "hypothesis", "mypy", "pytest", "pytest-cov", "pytest-timeout", "ruff", "tox", "types-pygments"] + +[[package]] +name = "platformdirs" +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "protobuf" +version = "5.27.2" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "protobuf-5.27.2-cp310-abi3-win32.whl", hash = "sha256:354d84fac2b0d76062e9b3221f4abbbacdfd2a4d8af36bab0474f3a0bb30ab38"}, + {file = "protobuf-5.27.2-cp310-abi3-win_amd64.whl", hash = "sha256:0e341109c609749d501986b835f667c6e1e24531096cff9d34ae411595e26505"}, + {file = "protobuf-5.27.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a109916aaac42bff84702fb5187f3edadbc7c97fc2c99c5ff81dd15dcce0d1e5"}, + {file = "protobuf-5.27.2-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:176c12b1f1c880bf7a76d9f7c75822b6a2bc3db2d28baa4d300e8ce4cde7409b"}, + {file = "protobuf-5.27.2-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:b848dbe1d57ed7c191dfc4ea64b8b004a3f9ece4bf4d0d80a367b76df20bf36e"}, + {file = "protobuf-5.27.2-cp38-cp38-win32.whl", hash = "sha256:4fadd8d83e1992eed0248bc50a4a6361dc31bcccc84388c54c86e530b7f58863"}, + {file = "protobuf-5.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:610e700f02469c4a997e58e328cac6f305f649826853813177e6290416e846c6"}, + {file = "protobuf-5.27.2-cp39-cp39-win32.whl", hash = "sha256:9e8f199bf7f97bd7ecebffcae45ebf9527603549b2b562df0fbc6d4d688f14ca"}, + {file = "protobuf-5.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:7fc3add9e6003e026da5fc9e59b131b8f22b428b991ccd53e2af8071687b4fce"}, + {file = "protobuf-5.27.2-py3-none-any.whl", hash = "sha256:54330f07e4949d09614707c48b06d1a22f8ffb5763c159efd5c0928326a91470"}, + {file = "protobuf-5.27.2.tar.gz", hash = "sha256:f3ecdef226b9af856075f28227ff2c90ce3a594d092c39bee5513573f25e2714"}, +] + +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pylint" +version = "3.2.7" +description = "python code static checker" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "pylint-3.2.7-py3-none-any.whl", hash = "sha256:02f4aedeac91be69fb3b4bea997ce580a4ac68ce58b89eaefeaf06749df73f4b"}, + {file = "pylint-3.2.7.tar.gz", hash = "sha256:1b7a721b575eaeaa7d39db076b6e7743c993ea44f57979127c517c6c572c803e"}, +] + +[package.dependencies] +astroid = ">=3.2.4,<=3.3.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = [ + {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, +] +isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" +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)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pytest" +version = "8.3.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "5.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytz" +version = "2024.2" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, + {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "requests" +version = "2.32.3" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "ruff" +version = "0.6.9" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"}, + {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"}, + {file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039"}, + {file = "ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d"}, + {file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"}, + {file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"}, + {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"}, +] + +[[package]] +name = "setuptools" +version = "75.1.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"}, + {file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "tomli" +version = "2.0.2" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, + {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, +] + +[[package]] +name = "tomlkit" +version = "0.13.2" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, +] + +[[package]] +name = "types-protobuf" +version = "5.28.0.20240924" +description = "Typing stubs for protobuf" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-protobuf-5.28.0.20240924.tar.gz", hash = "sha256:d181af8a256e5a91ce8d5adb53496e880efd9144c7d54483e3653332b60296f0"}, + {file = "types_protobuf-5.28.0.20240924-py3-none-any.whl", hash = "sha256:5cecf612ccdefb7dc95f7a51fb502902f20fc2e6681cd500184aaa1b3931d6a7"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +description = "Runtime inspection utilities for typing module." +optional = false +python-versions = "*" +files = [ + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, +] + +[package.dependencies] +mypy-extensions = ">=0.3.0" +typing-extensions = ">=3.7.4" + +[[package]] +name = "urllib3" +version = "2.2.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "wheel" +version = "0.44.0" +description = "A built-package format for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "wheel-0.44.0-py3-none-any.whl", hash = "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f"}, + {file = "wheel-0.44.0.tar.gz", hash = "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"}, +] + +[package.extras] +test = ["pytest (>=6.0.0)", "setuptools (>=65)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "6faffcadb09720da42bda62ed78feb40645ddcb0f3ca31774389bd759897a292" diff --git a/python/remotivelabs-broker/poetry.toml b/python/remotivelabs-broker/poetry.toml new file mode 100644 index 0000000..24a1ce5 --- /dev/null +++ b/python/remotivelabs-broker/poetry.toml @@ -0,0 +1,2 @@ +virtualenvs.in-project = true +virtualenvs.prefer-active-python = true diff --git a/python/remotivelabs-broker/pyproject.toml b/python/remotivelabs-broker/pyproject.toml index d48275b..3821ac3 100644 --- a/python/remotivelabs-broker/pyproject.toml +++ b/python/remotivelabs-broker/pyproject.toml @@ -1,22 +1,14 @@ -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[project] +[tool.poetry] name = "remotivelabs-broker" description = 'RemotiveLabs Broker gRPC API' +version = "0.2.0-beta1" readme = "README.md" -requires-python = ">=3.7" license = "Apache-2.0" -keywords = [ - "automotive", - "autotech", - "networking", - "CAN", -] -authors = [ - { name = "Support", email = "support@remotivelabs.com" }, -] +homepage = "https://remotivelabs.com/" +repository = "https://github.com/remotivelabs/remotivelabs-apis" +documentation = "https://docs.remotivelabs.com/apis/python/remotivelabs/broker" +authors = ["Support "] +keywords = ["automotive", "autotech", "networking", "CAN"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", @@ -28,75 +20,125 @@ classifiers = [ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Communications", "Topic :: Internet", "Topic :: Scientific/Engineering :: Information Analysis", ] -dependencies = [ - "grpc-interceptor~=0.14", - "grpcio~=1.44", - "grpc-stubs~=1.53.0.5", - "requests~=2.21", - "protobuf>=3.19.0,<=3.20.1", - "mypy-protobuf~=3.3.0", - "types-protobuf~=4.24.0.20240106", - "grpc-interceptor" -] -dynamic = ["version"] +packages = [{ include = "remotivelabs" }] -[project.urls] -Homepage = "https://remotivelabs.com/" -Documentation = "https://docs.remotivelabs.com/apis/python/remotivelabs/broker" +[tool.poetry.urls] Issues = "https://github.com/remotivelabs/remotivelabs-apis/issues" -Source = "https://github.com/remotivelabs/remotivelabs-apis/tree/main/python/remotivelabs-broker" - -[project.optional-dependencies] -default = [ - "pytest-cov~=3.0", - "pytest-pep8~=1.0", - "pytest~=7.1", - "pdoc~=12.2", -] -[tool.hatch.version] -path = "remotivelabs/broker/__about__.py" +[tool.poetry.dependencies] +python = "^3.8" +requests = "^2.32" +grpcio = "1.66.2" +# Make sure to use the protobuf version specified in grpcio-tools: +# https://github.com/grpc/grpc/blob/v1.66.2/tools/distrib/python/grpcio_tools/grpc_version.py +protobuf = "5.27.2" +grpc-interceptor = "^0.15" # can be removed when we drop support for remotivelabs.broker.sync -[tool.hatch.envs.default] -python = "python3" +[tool.poetry.group.dev.dependencies] +grpcio-tools = "1.66.2" +types-protobuf = "^5.27.0" +grpc-stubs = "^1.53" # can be removed when we drop support for remotivelabs.broker.sync -[tool.hatch.envs.default.scripts] -cov = "pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=remotivelabs --cov=tests" -no-cov = "cov --no-cov" -generate_stubs = "sh build_proto.sh" -generate_doc = "sh misc/build_doc.sh" +[tool.poetry.group.test.dependencies] +pytest = "^8.3" +pytest-cov = "^5.0" -[tool.pyright] -include = ["remotivelabs"] +[tool.poetry.group.lint.dependencies] +ruff = "^0.6.9" +pylint = "^3.2.7" +mypy = "^1.11.2" -[[tool.hatch.envs.test.matrix]] -python = ["38", "39", "310", "311"] +[tool.poetry.group.docs.dependencies] +pdoc = "^12.2" +json-schema-for-humans = "^1.0" -[tool.coverage.run] -branch = true -parallel = true -omit = [ - "remotivelabs/broker/__about__.py", -] +[tool.poe.tasks] +test = "pytest --cov=remotivelabs.broker" +test-server = "pytest -m server --cov=remotivelabs.broker" +pylint = [{ cmd = "pylint ." }] +lint = [{ cmd = "ruff check ." }, { cmd = "ruff format --check --diff ." }] +format = [{ cmd = "ruff format ." }, { cmd = "ruff check --fix ." }] +mypy = [{ cmd = "mypy -p remotivelabs.broker -p misc -p tests" }] +check = ["lint", "mypy", "pylint"] [tool.pytest.ini_options] +addopts = "-v -m 'not server'" markers = [ - "server: Run test towards a live server.", + "server: marks tests that require a live server (deselect with '-m \"not server\"')", +] + +[tool.ruff] +line-length = 140 + +[tool.ruff.lint] +select = [ + "ARG", + "B034", + "C901", + "E", + "EXE", + "F", + "FA", + "I", + "N", + "UP032", + "RET", + "W", ] -[tool.coverage.report] -exclude_lines = [ - "no cov", - "if __name__ == .__main__.:", - "if TYPE_CHECKING:", +[tool.pylint] +recursive = true +ignore-paths = ['^.venv/.*$'] + +[tool.pylint.format] +max-line-length = 140 +max-module-lines = 1000 + +[tool.pylint.messages_control] +disable = [ + 'wrong-import-order', + 'missing-module-docstring', + 'missing-class-docstring', + 'missing-function-docstring', + 'duplicate-code', + 'logging-fstring-interpolation', + 'too-few-public-methods', + 'no-member', ] -[tool.hatch.build.targets.wheel] -packages = ["remotivelabs"] +[tool.mypy] +python_version = "3.8" +namespace_packages = true +explicit_package_bases = true +mypy_path = "." +packages = ["remotivelabs.broker", "misc", "tests"] + +# See https://mypy.readthedocs.io/en/stable/config_file.html +disallow_untyped_calls = false +check_untyped_defs = true +warn_return_any = true +warn_unused_ignores = true +hide_error_codes = false + +[[tool.mypy.overrides]] +# A field in diagnostics proto file is accidentally named same as the type (bytes bytes), so we need to ignore the type warning. +module = "remotivelabs.broker.generated.sync.diagnostics_api_pb2" +disable_error_code = ["valid-type"] + +[[tool.mypy.overrides]] +# Also, it seems experimental features are missing in type definitions +module = "remotivelabs.broker.generated.*" +disable_error_code = ["attr-defined"] + +[[tool.mypy.overrides]] +# We ignore stuff in sync, they are deprecated +module = "remotivelabs.broker.sync.*" +ignore_errors = true + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/python/remotivelabs-broker/remotivelabs/broker/__about__.py b/python/remotivelabs-broker/remotivelabs/broker/__about__.py index f3062b2..09e2860 100644 --- a/python/remotivelabs-broker/remotivelabs/broker/__about__.py +++ b/python/remotivelabs-broker/remotivelabs/broker/__about__.py @@ -1,5 +1,9 @@ # SPDX-FileCopyrightText: 2022-present remotiveLabs # # SPDX-License-Identifier: Apache-2.0 +from importlib.metadata import PackageNotFoundError, version -__version__ = "0.1.26" +try: + __version__ = version("remotivelabs-broker") +except PackageNotFoundError: + __version__ = "unknown" diff --git a/python/remotivelabs-broker/remotivelabs/broker/__init__.py b/python/remotivelabs-broker/remotivelabs/broker/__init__.py index 984e275..8fbc345 100644 --- a/python/remotivelabs-broker/remotivelabs/broker/__init__.py +++ b/python/remotivelabs-broker/remotivelabs/broker/__init__.py @@ -1,37 +1,51 @@ """ -remotiveLabs Python API for remotiveBroker. -See `version` below. +RemotiveLabs Python API for RemotiveBroker. + +This API uses protobuffer and gRPC stubs directly, available in the submodules: +- `remotivelabs.broker.common_pb2`. +- `remotivelabs.broker.common_pb2_grpc`. +- `remotivelabs.broker.diagnostics_api_pb2`. +- `remotivelabs.broker.diagnostics_api_pb2_grpc`. +- `remotivelabs.broker.functional_api_pb2`. +- `remotivelabs.broker.functional_api_pb2_grpc`. +- `remotivelabs.broker.network_api_pb2`. +- `remotivelabs.broker.network_api_pb2_grpc`. +- `remotivelabs.broker.system_api_pb2`. +- `remotivelabs.broker.system_api_pb2_grpc`. +- `remotivelabs.broker.traffic_api_pb2`. +- `remotivelabs.broker.traffic_api_pb2_grpc`. In addition to return codes, this package uses logging to convey operational -status. Logging is done to the name space "com.remotivelabs.broker". +status. Logging is done to the namespace "remotivelabs.broker". -As a user, enable basic logging in your application with: ```python -logging.basicConfig() +# Disable logging for this package: +logging.getLogger("remotivelabs.broker").propagate = False ``` - -Disable logging for this package: - -```python -logging.getLogger("com.remotivelabs.broker").propagate = False -``` - -Use sub module: `remotivelabs.broker.sync`. """ # SPDX-FileCopyrightText: 2022-present remotiveLabs # # SPDX-License-Identifier: Apache-2.0 - -import logging - from .__about__ import __version__ - -log: logging.Logger = logging.getLogger("com.remotivelabs.broker") -"""Package logging interface""" - -log.addHandler(logging.NullHandler()) +from ._log import configure_logging +from .generated.sync import ( + common_pb2, # noqa: F401 + common_pb2_grpc, # noqa: F401 + diagnostics_api_pb2, # noqa: F401 + diagnostics_api_pb2_grpc, # noqa: F401 + functional_api_pb2, # noqa: F401 + functional_api_pb2_grpc, # noqa: F401 + network_api_pb2, # noqa: F401 + network_api_pb2_grpc, # noqa: F401 + system_api_pb2, # noqa: F401 + system_api_pb2_grpc, # noqa: F401 + traffic_api_pb2, # noqa: F401 + traffic_api_pb2_grpc, # noqa: F401 +) version: str = __version__ """Library version""" + +configure_logging() diff --git a/python/remotivelabs-broker/remotivelabs/broker/_log.py b/python/remotivelabs-broker/remotivelabs/broker/_log.py new file mode 100644 index 0000000..b20e558 --- /dev/null +++ b/python/remotivelabs-broker/remotivelabs/broker/_log.py @@ -0,0 +1,11 @@ +""" +Configure library logger + +See https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library +""" + +import logging + + +def configure_logging() -> None: + logging.getLogger("remotivelabs.broker").addHandler(logging.NullHandler()) diff --git a/python/remotivelabs-broker/remotivelabs/broker/sync/__init__.py b/python/remotivelabs-broker/remotivelabs/broker/sync/__init__.py index 6ab3495..e22ed8d 100644 --- a/python/remotivelabs-broker/remotivelabs/broker/sync/__init__.py +++ b/python/remotivelabs-broker/remotivelabs/broker/sync/__init__.py @@ -3,26 +3,13 @@ Create a connection with the method `remotivelabs.broker.sync.create_channel`. -This API uses protobuffer and gRPC stubs directly. Which are availble in the submodules: -- `remotivelabs.broker.sync.common_pb2`. -- `remotivelabs.broker.sync.common_pb2_grpc`. -- `remotivelabs.broker.sync.diagnostics_api_pb2`. -- `remotivelabs.broker.sync.diagnostics_api_pb2_grpc`. -- `remotivelabs.broker.sync.functional_api_pb2`. -- `remotivelabs.broker.sync.functional_api_pb2_grpc`. -- `remotivelabs.broker.sync.network_api_pb2`. -- `remotivelabs.broker.sync.network_api_pb2_grpc`. -- `remotivelabs.broker.sync.system_api_pb2`. -- `remotivelabs.broker.sync.system_api_pb2_grpc`. -- `remotivelabs.broker.sync.traffic_api_pb2`. -- `remotivelabs.broker.sync.traffic_api_pb2_grpc`. - For an example on how to use these we recommend looking at the samples for this library. Which is available at the repository remotiveLabs samples: Link: . """ +# Prefer import from root module. We keep this import for backwards compatibility. from ..generated.sync import ( common_pb2, # noqa: F401 common_pb2_grpc, # noqa: F401 @@ -37,7 +24,13 @@ traffic_api_pb2, # noqa: F401 traffic_api_pb2_grpc, # noqa: F401 ) -from .client import BrokerException, Client, SignalIdentifier, SignalsInFrame, SignalValue +from .client import ( + BrokerException, + Client, + SignalIdentifier, + SignalsInFrame, + SignalValue, +) from .helper import ( act_on_scripted_signal, act_on_signal, diff --git a/python/remotivelabs-broker/remotivelabs/broker/sync/client.py b/python/remotivelabs-broker/remotivelabs/broker/sync/client.py index 8232c02..3d7664f 100644 --- a/python/remotivelabs-broker/remotivelabs/broker/sync/client.py +++ b/python/remotivelabs-broker/remotivelabs/broker/sync/client.py @@ -8,8 +8,12 @@ import grpc -from ..generated.sync import network_api_pb2 as network_api -from ..generated.sync import network_api_pb2_grpc, system_api_pb2_grpc, traffic_api_pb2_grpc +from .. import network_api_pb2 as network_api +from .. import ( + network_api_pb2_grpc, + system_api_pb2_grpc, + traffic_api_pb2_grpc, +) from . import helper as br from .signalcreator import SignalCreator @@ -112,9 +116,8 @@ def __iter__(self): def __next__(self): try: result = self.signals[self.index] - # pylint: disable=raise-missing-from - except IndexError: - raise StopIteration + except IndexError as ex: + raise StopIteration from ex self.index += 1 return result @@ -132,10 +135,11 @@ def parse(signal_id: str) -> SignalIdentifier: return SignalIdentifier(s[1], s[0]) -class BrokerException(Exception): +class BrokerException(Exception): # noqa: N818 pass +# pylint: disable=too-many-instance-attributes class Client: def __init__(self, client_id: str = "broker_client"): self._signal_creator: SignalCreator @@ -195,7 +199,7 @@ def to_protobuf_signal(s: SignalIdentifier): lambda sub: (wait_for_subscription_queue.put((self.client_id, sub))), ), ).start() - # Wait for subscription + client_id, subscription = wait_for_subscription_queue.get() return subscription @@ -209,7 +213,6 @@ def _on_signals(self, signals_in_frame: network_api.Signals, callback): self.on_signals(SignalsInFrame(list(map(SignalValue, signals_in_frame)))) # type: ignore[call-overload] def list_signal_names(self) -> List[SignalIdentifier]: - # Lists available signals configuration = self._system_stub.GetConfiguration(br.common_pb2.Empty()) signal_names: List[SignalIdentifier] = [] diff --git a/python/remotivelabs-broker/remotivelabs/broker/sync/helper.py b/python/remotivelabs-broker/remotivelabs/broker/sync/helper.py index 87a4d1c..e1e779a 100644 --- a/python/remotivelabs-broker/remotivelabs/broker/sync/helper.py +++ b/python/remotivelabs-broker/remotivelabs/broker/sync/helper.py @@ -2,6 +2,7 @@ import hashlib import itertools +import logging import ntpath import os import posixpath @@ -12,8 +13,19 @@ import grpc from grpc_interceptor import ClientCallDetails, ClientInterceptor -from .. import log -from ..generated.sync import common_pb2, network_api_pb2, network_api_pb2_grpc, system_api_pb2, system_api_pb2_grpc +from .. import ( + common_pb2, + network_api_pb2, + network_api_pb2_grpc, + system_api_pb2, + system_api_pb2_grpc, +) + +_logger = logging.getLogger(__name__) + + +# pylint: disable=protected-access +# pylint: disable=too-many-arguments class HeaderInterceptor(ClientInterceptor): @@ -95,9 +107,8 @@ def publish_signals(client_id, stub, signals_with_payload, frequency: int = 0) - try: stub.PublishSignals(publisher_info) - # pylint: disable=protected-access - except grpc._channel._Rendezvous as err: # type:ignore[attr-defined] - log.error(err) + except grpc._channel._Rendezvous: # type:ignore[attr-defined] + _logger.exception("A Rendezvous error occurred") def printer(signals: Sequence[common_pb2.SignalId]) -> None: @@ -108,7 +119,7 @@ def printer(signals: Sequence[common_pb2.SignalId]) -> None: """ for signal in signals: - log.info(f"{signal} {signal.namespace.name}") + _logger.info(f"{signal} {signal.namespace.name}") def get_sha256(path: str) -> str: @@ -118,11 +129,9 @@ def get_sha256(path: str) -> str: :param path: Path to file :rtype int: """ - with open(path, "rb") as f: b = f.read() # read entire file as bytes - readable_hash = hashlib.sha256(b).hexdigest() - return readable_hash + return hashlib.sha256(b).hexdigest() def generate_data(file, dest_path, chunk_size, sha256) -> Generator[system_api_pb2.FileUploadRequest, None, None]: @@ -147,13 +156,13 @@ def upload_file(system_stub: system_api_pb2_grpc.SystemServiceStub, path: str, d """ sha256 = get_sha256(path) - log.debug(f"SHA256 for file {path}: {sha256}") + _logger.debug(f"SHA256 for file {path}: {sha256}") with open(path, "rb") as file: # make sure path is unix style (necessary for windows, and does no harm om # linux) upload_iterator = generate_data(file, dest_path.replace(ntpath.sep, posixpath.sep), 1000000, sha256) response = system_stub.UploadFile(upload_iterator, compression=grpc.Compression.Gzip) - log.debug(f"Uploaded {path} with response {response}") + _logger.debug(f"Uploaded {path} with response {response}") def download_file(system_stub: system_api_pb2_grpc.SystemServiceStub, path: str, dest_path: str) -> None: @@ -198,7 +207,7 @@ def reload_configuration( request = common_pb2.Empty() response = system_stub.ReloadConfiguration(request, timeout=60000) - log.debug(f"Reload configuration with response {response}") + _logger.debug(f"Reload configuration with response {response}") def check_license( @@ -231,8 +240,7 @@ def act_on_signal( :param fun: Callback for receiving signals update :param on_subscribed: Callback for successful subscription """ - - log.debug("Subscription started") + _logger.debug("Subscription started") sub_info = network_api_pb2.SubscriberConfig( clientId=client_id, @@ -243,25 +251,24 @@ def act_on_signal( subscripton = network_stub.SubscribeToSignals(sub_info, timeout=None) if on_subscribed: on_subscribed(subscripton) - log.debug("Waiting for signal...") + + _logger.debug("Waiting for signal...") for subs_counter in subscripton: fun(subs_counter.signal) + except grpc._channel._Rendezvous: # type:ignore[attr-defined] + _logger.exception("A Rendezvous error occurred") except grpc.RpcError as e: # Only try to cancel if cancel was not already attempted - # pylint: disable=no-member if e.code() != grpc.StatusCode.CANCELLED: try: subscripton.cancel() - print("A gRPC error occurred:") - print(e) + _logger.exception("A gRPC error occurred") except grpc.RpcError: pass - # pylint: disable=protected-access, bad-except-order - except grpc._channel._Rendezvous as err: # type:ignore[attr-defined] - log.error(err) + # reload, alternatively non-existing signal - log.debug("Subscription terminated") + _logger.debug("Subscription terminated") def act_on_scripted_signal( @@ -283,7 +290,7 @@ def act_on_scripted_signal( :param on_subscribed: Callback for successful subscription """ - log.debug("Subscription with mapping code started...") + _logger.debug("Subscription with mapping code started...") sub_info = network_api_pb2.SubscriberWithScriptConfig( clientId=client_id, @@ -294,20 +301,20 @@ def act_on_scripted_signal( subscription = network_stub.SubscribeToSignalWithScript(sub_info, timeout=None) if on_subscribed: on_subscribed(subscription) - log.debug("Waiting for signal...") + + _logger.debug("Waiting for signal...") for subs_counter in subscription: fun(subs_counter.signal) - except grpc.RpcError as e: + except grpc._channel._Rendezvous: # type:ignore[attr-defined] + _logger.exception("A Rendezvous error occurred") + + except grpc.RpcError: + _logger.exception("A gRPC error occurred") try: subscription.cancel() - print("A gRPC error occurred:") - print(e) except grpc.RpcError: pass - # pylint: disable=protected-access, bad-except-order - except grpc._channel._Rendezvous as err: # type:ignore[attr-defined] - log.error(err) # reload, alternatively non-existing signal - log.debug("Subscription terminated") + _logger.debug("Subscription terminated") diff --git a/python/remotivelabs-broker/remotivelabs/broker/sync/signalcreator.py b/python/remotivelabs-broker/remotivelabs/broker/sync/signalcreator.py index ddf4b6c..e6b9d7b 100644 --- a/python/remotivelabs-broker/remotivelabs/broker/sync/signalcreator.py +++ b/python/remotivelabs-broker/remotivelabs/broker/sync/signalcreator.py @@ -3,20 +3,24 @@ import logging from typing import Any, Dict, List, Optional, Sequence, TypeVar -from ..generated.sync import common_pb2, network_api_pb2, system_api_pb2_grpc +from .. import common_pb2, network_api_pb2, system_api_pb2_grpc -T = TypeVar("T") +_logger = logging.getLogger(__name__) -_logger = logging.getLogger("remotivelabs.SignalCreator") _MSG_DUPLICATE = "Warning duplicated (namespace.signal): {}, to avoid" + 'ambiguity set "short_names": false in your interfaces.json on {}' +T = TypeVar("T") + + +# pylint: disable=invalid-name +# pylint: disable=broad-exception-raised + -# pylint: disable=C0103 class MetaGetter: def __init__(self, proto_message): self.meta = proto_message - def _getDefault(self, field: T, default: Optional[T]) -> T: + def _getDefault(self, field: T, default: Optional[T]) -> T: # noqa: N802 if field is not None: return field @@ -25,51 +29,51 @@ def _getDefault(self, field: T, default: Optional[T]) -> T: raise Exception("Failed to retrieve meta data field") - def getDescription(self, default: Optional[str] = None) -> str: + def getDescription(self, default: Optional[str] = None) -> str: # noqa: N802 """Get protobuffer MetaData field description""" return self._getDefault(self.meta.description, default) - def getUnit(self, default: Optional[str] = None) -> str: + def getUnit(self, default: Optional[str] = None) -> str: # noqa: N802 """Get protobuffer MetaData field unit""" return self._getDefault(self.meta.unit, default) - def getMax(self, default: Optional[float] = None) -> float: + def getMax(self, default: Optional[float] = None) -> float: # noqa: N802 """Get protobuffer MetaData field max""" return self._getDefault(self.meta.max, default) - def getMin(self, default: Optional[float] = None) -> float: + def getMin(self, default: Optional[float] = None) -> float: # noqa: N802 """Get protobuffer MetaData field min""" return self._getDefault(self.meta.min, default) - def getSize(self, default: Optional[int] = None) -> int: + def getSize(self, default: Optional[int] = None) -> int: # noqa: N802 """Get protobuffer MetaData field size""" return self._getDefault(self.meta.size, default) - def getIsRaw(self, default: Optional[bool] = None) -> bool: + def getIsRaw(self, default: Optional[bool] = None) -> bool: # noqa: N802 """Get protobuffer MetaData field isRaw""" return self._getDefault(self.meta.isRaw, default) - def getFactor(self, default: Optional[float] = None) -> float: + def getFactor(self, default: Optional[float] = None) -> float: # noqa: N802 """Get protobuffer MetaData field factor""" return self._getDefault(self.meta.factor, default) - def getOffset(self, default: Optional[float] = None) -> float: + def getOffset(self, default: Optional[float] = None) -> float: # noqa: N802 """Get protobuffer MetaData field offset""" return self._getDefault(self.meta.offset, default) - def getSenders(self, default: Optional[Sequence[str]] = None) -> Sequence[str]: + def getSenders(self, default: Optional[Sequence[str]] = None) -> Sequence[str]: # noqa: N802 """Get protobuffer MetaData field sender""" return self._getDefault(self.meta.sender, default) - def getReceivers(self, default: Optional[Sequence[str]] = None) -> Sequence[str]: + def getReceivers(self, default: Optional[Sequence[str]] = None) -> Sequence[str]: # noqa: N802 """Get protobuffer MetaData field receiver""" return self._getDefault(self.meta.receiver, default) - def getCycleTime(self, default: Optional[float] = None) -> float: + def getCycleTime(self, default: Optional[float] = None) -> float: # noqa: N802 """Get protobuffer MetaData field cycleTime""" return self._getDefault(self.meta.cycleTime, default) - def getStartValue(self, default: Optional[float] = None) -> float: + def getStartValue(self, default: Optional[float] = None) -> float: # noqa: N802 """Get protobuffer MetaData field startValue""" return self._getDefault(self.meta.startValue, default) @@ -79,7 +83,11 @@ class SignalCreator: Class for prepearing and writing signals via gRPC. """ - def __init__(self, system_stub: system_api_pb2_grpc.SystemServiceStub, namespaces: List[str] | None = None): + def __init__( + self, + system_stub: system_api_pb2_grpc.SystemServiceStub, + namespaces: List[str] | None = None, + ): self._sinfos: Dict[Any, Any] = {} self._virtual: List[Any] = [] self._networks: Dict[Any, Any] = {} @@ -210,8 +218,3 @@ def signal_with_payload(self, name: str, namespace_name: str, value_pair, allow_ params = {"id": signal, key: value} return network_api_pb2.Signal(**params) - - # Above is simlar as this, but parameterised. - # return network_api_pb2.Signal( - # id=signal, value_dict.get_key=value_dict["integer"] - # ) diff --git a/python/remotivelabs-broker/tests/__init__.py b/python/remotivelabs-broker/tests/__init__.py deleted file mode 100644 index a48296a..0000000 --- a/python/remotivelabs-broker/tests/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-FileCopyrightText: 2022-present remotiveLabs -# -# SPDX-License-Identifier: Apache-2.0 diff --git a/python/remotivelabs-broker/tests/test_live.py b/python/remotivelabs-broker/tests/test_live.py index a8ed9c0..cf84b54 100644 --- a/python/remotivelabs-broker/tests/test_live.py +++ b/python/remotivelabs-broker/tests/test_live.py @@ -18,14 +18,12 @@ def __init__(self): # Setup broker with predefined settings -@pytest.fixture @pytest.fixture(name="broker_connection") def fixture_broker_connection(): return Connection() # Setup broker configured for testing -@pytest.fixture @pytest.fixture(name="broker_configured") def fixture_broker_configured(broker_connection): br.upload_folder(broker_connection.system_stub, "tests/configuration_udp") diff --git a/rust/README.md b/rust/README.md new file mode 100644 index 0000000..6638287 --- /dev/null +++ b/rust/README.md @@ -0,0 +1,28 @@ +# RemotiveBroker Rust API + +`remotivelabs-broker` - Rust library with gRPC-bindings and utility functions. + +## Getting started + +```bash +cd rust/remotivelabs-broker + +# build +cargo build +``` + +## Building + +```bash +cd rust/remotivelabs-broker + +cargo build +``` + +## Versioning + +Follow [Semantic versioning](https://semver.org/). Beta versions should be suffixed with `-beta*`, example `0.2.0-beta1`. + +## Publishing + +This library is not published. diff --git a/rust/remotivelabs-broker/Cargo.lock b/rust/remotivelabs-broker/Cargo.lock index e1e83e0..8e10e40 100644 --- a/rust/remotivelabs-broker/Cargo.lock +++ b/rust/remotivelabs-broker/Cargo.lock @@ -885,7 +885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] -name = "remotive-broker" +name = "remotivelabs-broker" version = "0.1.0" dependencies = [ "clap", diff --git a/rust/remotivelabs-broker/Cargo.toml b/rust/remotivelabs-broker/Cargo.toml index b8bc305..fa2f2f6 100644 --- a/rust/remotivelabs-broker/Cargo.toml +++ b/rust/remotivelabs-broker/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "remotive-broker" +name = "remotivelabs-broker" version = "0.1.0" -authors = [ "RemotiveLabs support ", "Lind, Niclas "] +authors = ["RemotiveLabs support "] edition = "2021" [dependencies] @@ -9,7 +9,13 @@ futures = "0.3.19" path-slash = "0.1.4" prost = "0.9.0" sha2 = "0.10.1" -tokio = { version = "1.14.0", features = ["rt-multi-thread", "time", "fs", "macros", "net"] } +tokio = { version = "1.14.0", features = [ + "rt-multi-thread", + "time", + "fs", + "macros", + "net", +] } tonic = { version = "0.6.2", features = ["tls", "tls-roots"] } walkdir = "2.3.2" diff --git a/rust/remotivelabs-broker/README.md b/rust/remotivelabs-broker/README.md index 99a5f21..ddb3fdf 100644 --- a/rust/remotivelabs-broker/README.md +++ b/rust/remotivelabs-broker/README.md @@ -1,9 +1,24 @@ -# RemotiveLabs Broker +# RemotiveBroker Rust API + Rust library with gRPC-bindings and utility functions. -gRPC bindings are generated from [this source](../../proto/) when compiling the project. +## Usage + +```rust +use remotive_broker::{ + Connection, +}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let mut con = Connection::new("http://localhost:50051".to_string(), None).await?; + + println!("Checking license..."); + con.check_license().await?; -This project is contributed by _Niclas Lind_ (@niclaslind). + Ok(()) +} +``` ## Examples diff --git a/rust/remotivelabs-broker/build.rs b/rust/remotivelabs-broker/build.rs index e41aff8..38ba352 100644 --- a/rust/remotivelabs-broker/build.rs +++ b/rust/remotivelabs-broker/build.rs @@ -1,7 +1,7 @@ fn main() -> Result<(), Box> { tonic_build::configure() .build_server(false) - .out_dir("src/remotive_api") + .out_dir("src/generated") .compile( &[ "common.proto", diff --git a/rust/remotivelabs-broker/examples/README.md b/rust/remotivelabs-broker/examples/README.md new file mode 100644 index 0000000..d090dd0 --- /dev/null +++ b/rust/remotivelabs-broker/examples/README.md @@ -0,0 +1 @@ +# `remotivelabs-broker` examples diff --git a/rust/remotivelabs-broker/examples/pub_client.rs b/rust/remotivelabs-broker/examples/pub_client.rs index 154783f..ee82aa5 100644 --- a/rust/remotivelabs-broker/examples/pub_client.rs +++ b/rust/remotivelabs-broker/examples/pub_client.rs @@ -1,7 +1,7 @@ use std::io::Write; -use remotive_broker::{ - remotive_api::base::{ +use remotivelabs_broker::{ + generated::base::{ signal::Payload::Integer, ClientId, NameSpace, PublisherConfig, Signal, SignalId, Signals, }, Connection, diff --git a/rust/remotivelabs-broker/examples/sub_client.rs b/rust/remotivelabs-broker/examples/sub_client.rs index 9c238a4..a76403a 100644 --- a/rust/remotivelabs-broker/examples/sub_client.rs +++ b/rust/remotivelabs-broker/examples/sub_client.rs @@ -1,5 +1,5 @@ -use remotive_broker::{ - remotive_api::base::{ClientId, NameSpace, SignalId, SignalIds, SubscriberConfig}, +use remotivelabs_broker::{ + generated::base::{ClientId, NameSpace, SignalId, SignalIds, SubscriberConfig}, Connection, }; use std::{thread, time}; diff --git a/rust/remotivelabs-broker/examples/subscribe.rs b/rust/remotivelabs-broker/examples/subscribe.rs index 4decddd..633097a 100644 --- a/rust/remotivelabs-broker/examples/subscribe.rs +++ b/rust/remotivelabs-broker/examples/subscribe.rs @@ -2,8 +2,8 @@ use clap::Parser; use std::error::Error; use std::fmt; -use remotive_broker::{ - remotive_api::base::{ClientId, NameSpace, SignalId, SignalIds, SubscriberConfig}, +use remotivelabs_broker::{ + generated::base::{ClientId, NameSpace, SignalId, SignalIds, SubscriberConfig}, Connection, }; diff --git a/rust/remotivelabs-broker/src/remotive_api/.gitignore b/rust/remotivelabs-broker/src/generated/.gitignore similarity index 100% rename from rust/remotivelabs-broker/src/remotive_api/.gitignore rename to rust/remotivelabs-broker/src/generated/.gitignore diff --git a/rust/remotivelabs-broker/src/remotive_api/mod.rs b/rust/remotivelabs-broker/src/generated/mod.rs similarity index 100% rename from rust/remotivelabs-broker/src/remotive_api/mod.rs rename to rust/remotivelabs-broker/src/generated/mod.rs diff --git a/rust/remotivelabs-broker/src/lib.rs b/rust/remotivelabs-broker/src/lib.rs index a3b48dd..17c0eaf 100644 --- a/rust/remotivelabs-broker/src/lib.rs +++ b/rust/remotivelabs-broker/src/lib.rs @@ -3,12 +3,12 @@ use std::{error::Error, fs, path::Path}; use futures::{stream, Stream}; -use path_slash::PathExt; -use remotive_api::base::{ +use generated::base::{ file_upload_request::Data, functional_service_client::FunctionalServiceClient, network_service_client::NetworkServiceClient, system_service_client::SystemServiceClient, traffic_service_client::TrafficServiceClient, FileDescription, FileUploadRequest, }; +use path_slash::PathExt; use sha2::{Digest, Sha256}; use tonic::{ metadata::AsciiMetadataValue, @@ -18,9 +18,9 @@ use tonic::{ }; use walkdir::WalkDir; -use crate::remotive_api::base::{Empty, LicenseStatus}; +use crate::generated::base::{Empty, LicenseStatus}; -pub mod remotive_api; +pub mod generated; #[derive(Clone)] pub struct XApiIntercept {