mirror of
https://github.com/mozilla-services/syncstorage-rs.git
synced 2025-08-06 03:46:57 +02:00
feat: use poetry for dependency management (#1706)
Some checks are pending
Glean probe-scraper / glean-probe-scraper (push) Waiting to run
Some checks are pending
Glean probe-scraper / glean-probe-scraper (push) Waiting to run
feat: use poetry for dependency management
This commit is contained in:
parent
d716ac5d10
commit
f8715d4e91
@ -40,10 +40,11 @@ commands:
|
||||
name: Setup python
|
||||
command: |
|
||||
sudo apt-get update && sudo apt-get install -y python3-dev python3-pip
|
||||
pip3 install flake8 hawkauthlib konfig pyramid pyramid_hawkauth requests simplejson unittest2 WebTest WSGIProxy2
|
||||
pip3 install flake8 hawkauthlib konfig pyramid pyramid_hawkauth requests simplejson unittest2 WebTest WSGIProxy2 poetry
|
||||
# NOTE: Python3.12 requires `--break-system-packages`.
|
||||
# This command is run on the cimg/rust image, which is running python 3.10
|
||||
pip3 install -r requirements.txt
|
||||
poetry self add poetry-plugin-export
|
||||
poetry install --without dev --with tokenserver-unit-tests --no-interaction --no-ansi
|
||||
rust-check:
|
||||
steps:
|
||||
- run:
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -39,4 +39,7 @@ venv
|
||||
.vscode/settings.json
|
||||
|
||||
# circleci
|
||||
workspace
|
||||
workspace
|
||||
|
||||
# For poetry install
|
||||
.install.stamp
|
63
Dockerfile
63
Dockerfile
@ -18,9 +18,9 @@ ARG MYSQLCLIENT_PKG
|
||||
# cmake is required to build grpcio-sys for Spanner builds
|
||||
RUN \
|
||||
if [ "$MYSQLCLIENT_PKG" = libmysqlclient-dev ] ; then \
|
||||
# Fetch and load the MySQL public key.
|
||||
wget -qO- https://repo.mysql.com/RPM-GPG-KEY-mysql-2023 > /etc/apt/trusted.gpg.d/mysql.asc && \
|
||||
echo "deb https://repo.mysql.com/apt/debian/ bullseye mysql-8.0" >> /etc/apt/sources.list ; \
|
||||
# Fetch and load the MySQL public key.
|
||||
wget -qO- https://repo.mysql.com/RPM-GPG-KEY-mysql-2023 > /etc/apt/trusted.gpg.d/mysql.asc && \
|
||||
echo "deb https://repo.mysql.com/apt/debian/ bullseye mysql-8.0" >> /etc/apt/sources.list ; \
|
||||
fi && \
|
||||
apt-get -q update && \
|
||||
apt-get -q install -y --no-install-recommends $MYSQLCLIENT_PKG cmake
|
||||
@ -32,6 +32,12 @@ FROM chef AS builder
|
||||
ARG DATABASE_BACKEND
|
||||
ARG MYSQLCLIENT_PKG
|
||||
|
||||
ENV POETRY_HOME="/opt/poetry" \
|
||||
POETRY_VIRTUALENVS_IN_PROJECT=1 \
|
||||
POETRY_NO_INTERACTION=1
|
||||
|
||||
ENV PATH="$POETRY_HOME/bin:$PATH"
|
||||
|
||||
COPY . /app
|
||||
COPY --from=cacher /app/target /app/target
|
||||
COPY --from=cacher $CARGO_HOME /app/$CARGO_HOME
|
||||
@ -47,10 +53,21 @@ RUN \
|
||||
echo "deb https://repo.mysql.com/apt/debian/ bullseye mysql-8.0" >> /etc/apt/sources.list ; \
|
||||
fi && \
|
||||
apt-get -q update && \
|
||||
apt-get -q install -y --no-install-recommends $MYSQLCLIENT_PKG cmake golang-go python3-dev python3-pip python3-setuptools python3-wheel && \
|
||||
pip3 install -r requirements.txt && \
|
||||
apt-get -q install -y --no-install-recommends $MYSQLCLIENT_PKG cmake golang-go python3-dev python3-pip python3-setuptools python3-wheel pkg-config && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN curl -sSL https://install.python-poetry.org | python3 - && \
|
||||
ln -s $POETRY_HOME/bin/poetry /usr/local/bin/poetry && \
|
||||
poetry --version && \
|
||||
poetry config virtualenvs.create false && \
|
||||
poetry self add poetry-plugin-export
|
||||
|
||||
# Generating a requirements.txt from Poetry dependencies.
|
||||
# [tool.poetry.dependencies]
|
||||
RUN poetry export --no-interaction --without dev --output requirements.txt --without-hashes && \
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
|
||||
ENV PATH=$PATH:/root/.cargo/bin
|
||||
|
||||
RUN \
|
||||
@ -61,15 +78,20 @@ RUN \
|
||||
FROM docker.io/library/debian:bullseye-slim
|
||||
ARG MYSQLCLIENT_PKG
|
||||
|
||||
ENV POETRY_HOME="/opt/poetry" \
|
||||
POETRY_VIRTUALENVS_IN_PROJECT=1 \
|
||||
POETRY_NO_INTERACTION=1
|
||||
|
||||
ENV PATH="$POETRY_HOME/bin:$PATH"
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/requirements.txt /app
|
||||
COPY --from=builder /app/pyproject.toml /app/poetry.lock /app/
|
||||
|
||||
RUN \
|
||||
apt-get -q update && apt-get -qy install wget
|
||||
RUN \
|
||||
groupadd --gid 10001 app && \
|
||||
useradd --uid 10001 --gid 10001 --home /app --create-home app && \
|
||||
if [ "$MYSQLCLIENT_PKG" = libmysqlclient-dev ] ; then \
|
||||
RUN apt-get -q update && apt-get -qy install wget
|
||||
RUN groupadd --gid 10001 app && \
|
||||
useradd --uid 10001 --gid 10001 --home /app --create-home app
|
||||
RUN if [ "$MYSQLCLIENT_PKG" = libmysqlclient-dev ] ; then \
|
||||
# first, an apt-get update is required for gnupg, which is required for apt-key adv
|
||||
apt-get -q update && \
|
||||
# and ca-certificates needed for https://repo.mysql.com
|
||||
@ -80,14 +102,23 @@ RUN \
|
||||
fi && \
|
||||
# update again now that we trust repo.mysql.com
|
||||
apt-get -q update && \
|
||||
apt-get -q install -y build-essential $MYSQLCLIENT_PKG libssl-dev libffi-dev libcurl4 python3-dev python3-pip python3-setuptools python3-wheel cargo curl jq && \
|
||||
apt-get -q install -y build-essential $MYSQLCLIENT_PKG libssl-dev libffi-dev libcurl4 python3-dev python3-pip python3-setuptools python3-wheel cargo curl jq pkg-config && \
|
||||
# The python3-cryptography debian package installs version 2.6.1, but we
|
||||
# we want to use the version specified in requirements.txt. To do this,
|
||||
# we have to remove the python3-cryptography package here.
|
||||
apt-get -q remove -y python3-cryptography && \
|
||||
pip3 install -r /app/requirements.txt && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN curl -sSL https://install.python-poetry.org | python3 - && \
|
||||
ln -s $POETRY_HOME/bin/poetry /usr/local/bin/poetry && \
|
||||
poetry --version && \
|
||||
poetry config virtualenvs.create false && \
|
||||
poetry self add poetry-plugin-export
|
||||
# Generating a requirements.txt from Poetry dependencies.
|
||||
# [tool.poetry.dependencies]
|
||||
RUN poetry export --no-interaction --without dev --output requirements.txt --without-hashes && \
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
COPY --from=builder /app/bin /app/bin
|
||||
COPY --from=builder /app/syncserver/version.json /app
|
||||
COPY --from=builder /app/tools/spanner /app/tools/spanner
|
||||
@ -98,6 +129,12 @@ COPY --from=builder /app/scripts/start_mock_fxa_server.sh /app/scripts/start_moc
|
||||
COPY --from=builder /app/syncstorage-spanner/src/schema.ddl /app/schema.ddl
|
||||
|
||||
RUN chmod +x /app/scripts/prepare-spanner.sh
|
||||
|
||||
WORKDIR /app/tools/integration_tests/
|
||||
RUN poetry export --no-interaction --without dev --output requirements.txt --without-hashes
|
||||
WORKDIR /app/tools/tokenserver/
|
||||
RUN poetry export --no-interaction --without dev --output requirements.txt --without-hashes
|
||||
WORKDIR /app
|
||||
RUN pip3 install -r /app/tools/integration_tests/requirements.txt
|
||||
RUN pip3 install -r /app/tools/tokenserver/requirements.txt
|
||||
|
||||
|
45
Makefile
45
Makefile
@ -10,6 +10,18 @@ PATH_TO_SYNC_SPANNER_KEYS = `pwd`/service-account.json
|
||||
# https://github.com/mozilla-services/server-syncstorage
|
||||
PATH_TO_GRPC_CERT = ../server-syncstorage/local/lib/python2.7/site-packages/grpc/_cython/_credentials/roots.pem
|
||||
|
||||
POETRY := $(shell command -v poetry 2> /dev/null)
|
||||
INSTALL_STAMP := .install.stamp
|
||||
TOOLS_DIR := tools
|
||||
PROJECT_ROOT_DIR := ./
|
||||
ROOT_PYPROJECT_TOML := pyproject.toml
|
||||
HAWK_DIR := $(TOOLS_DIR)/hawk
|
||||
INTEGRATION_TEST_DIR := $(TOOLS_DIR)/integration_tests
|
||||
INTEGRATION_TEST_DIR_TOKENSERVER := $(TOOLS_DIR)/integration_tests/tokenserver
|
||||
SPANNER_DIR := $(TOOLS_DIR)/spanner
|
||||
TOKENSERVER_UTIL_DIR := $(TOOLS_DIR)/tokenserver
|
||||
LOAD_TEST_DIR := $(TOOLS_DIR)/tokenserver/loadtests
|
||||
|
||||
# In order to be consumed by the ETE Test Metric Pipeline, files need to follow a strict naming
|
||||
# convention: {job_number}__{utc_epoch_datetime}__{workflow}__{test_suite}__results{-index}.xml
|
||||
# TODO: update workflow name appropriately
|
||||
@ -137,3 +149,36 @@ merge_coverage_results:
|
||||
run_token_server_integration_tests:
|
||||
pip3 install -r tools/tokenserver/requirements.txt
|
||||
pytest tools/tokenserver --junit-xml=${INTEGRATION_JUNIT_XML}
|
||||
|
||||
.PHONY: install
|
||||
install: $(INSTALL_STAMP) ## Install dependencies with poetry
|
||||
$(INSTALL_STAMP): pyproject.toml poetry.lock
|
||||
@if [ -z $(POETRY) ]; then echo "Poetry could not be found. See https://python-poetry.org/docs/"; exit 2; fi
|
||||
$(POETRY) install
|
||||
touch $(INSTALL_STAMP)
|
||||
|
||||
hawk:
|
||||
# install dependencies for hawk token utility.
|
||||
$(POETRY) -V
|
||||
$(POETRY) install --directory=$(HAWK_DIR) --no-root
|
||||
|
||||
integration-test:
|
||||
# install dependencies for integration tests.
|
||||
$(POETRY) -V
|
||||
$(POETRY) install --directory=$(INTEGRATION_TEST_DIR) --no-root
|
||||
|
||||
spanner:
|
||||
# install dependencies for spanner utilities.
|
||||
$(POETRY) -V
|
||||
$(POETRY) install --directory=$(SPANNER_DIR) --no-root
|
||||
|
||||
tokenserver:
|
||||
# install dependencies for tokenserver utilities.
|
||||
$(POETRY) -V
|
||||
$(POETRY) install --directory=$(TOKENSERVER_UTIL_DIR) --no-root
|
||||
|
||||
tokenserver-load:
|
||||
# install dependencies for tokenserver load tests.
|
||||
$(POETRY) -V
|
||||
$(POETRY) install --directory=$(LOAD_TEST_DIR) --no-root
|
||||
|
||||
|
1692
poetry.lock
generated
Normal file
1692
poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
48
pyproject.toml
Normal file
48
pyproject.toml
Normal file
@ -0,0 +1,48 @@
|
||||
[project]
|
||||
name = "syncstorage-rs"
|
||||
version = "0.1.0"
|
||||
description = "Python dependencies for the root of the syncstorage-rs project"
|
||||
authors = [
|
||||
{name = "Taddes",email = "tkorris@mozilla.com"}
|
||||
]
|
||||
license = "Mozilla Public License Version 2.0"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9.2"
|
||||
|
||||
[tool.poetry]
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
cryptography = "^44.0.2"
|
||||
pyfxa = "^0.8.1"
|
||||
tokenlib = "^2.0.0"
|
||||
|
||||
[tool.poetry.group.tokenserver-unit-tests.dependencies]
|
||||
cryptography = "44.0.2"
|
||||
hawkauthlib = "^2.0.0"
|
||||
konfig = "^1.1"
|
||||
mysqlclient = "^2.2.7"
|
||||
psutil = "^7.0.0"
|
||||
pyjwt = "^2.10.1"
|
||||
pyramid = "^2.0.2"
|
||||
pyramid-hawkauth = "^2.0.0"
|
||||
pyfxa = "0.8.1"
|
||||
pytest = "^8.4.0"
|
||||
requests = "^2.32.4"
|
||||
simplejson = "^3.20.1"
|
||||
sqlalchemy = "1.4.46"
|
||||
tokenlib = "^2.0.0"
|
||||
webtest = "^3.0.6"
|
||||
wsgiproxy2 = "^0.5.1"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
mypy = "^1.16.0"
|
||||
pydocstyle = "^6.3.0"
|
||||
ruff = "^0.11.13"
|
||||
black = "^25.1.0"
|
||||
bandit = "^1.8.3"
|
||||
isort = "^6.0.1"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
@ -1,3 +0,0 @@
|
||||
cryptography==44.0.2
|
||||
pyfxa==0.8.1
|
||||
tokenlib==2.0.0
|
3
scripts/start_mock_fxa_server.sh
Normal file → Executable file
3
scripts/start_mock_fxa_server.sh
Normal file → Executable file
@ -1,4 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
python3 /app/tools/integration_tests/tokenserver/mock_fxa_server.py
|
||||
|
||||
python3 /app/tools/integration_tests/tokenserver/mock_fxa_server.py
|
@ -1,29 +1,50 @@
|
||||
# Make a Hawk compatible Auth header
|
||||
|
||||
1) The best way to install this is probably to set up a python virtual
|
||||
env.
|
||||
## Dependencies and Environment Setup:
|
||||
To use the syncstorage-rs `make_hawk_token.py` script, you'll need a Python =>3.10 development environment with `Poetry` installed. You can also directly call the script using `Poetry` as described in step 5.
|
||||
|
||||
`python3 -m venv venv && venv/bin/pip install -r requirements.txt`
|
||||
The easiest solution recommended to use `pyenv` and the `pyenv-virtualenv` plugin for your virtual environments
|
||||
as a way to isolate the dependencies from other directories.
|
||||
1. Install `pyenv` using the [latest documentation](https://github.com/pyenv/pyenv#installation) for your platform.
|
||||
2. Follow the instructions to install the `pyenv-virtualenv` plugin.
|
||||
See the [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv) documentation.
|
||||
3. Ensure you've added `pyenv` and `pyenv-virtualenv` to your PATH.
|
||||
|
||||
this will create a python virtual environment in the `/venv` directory.
|
||||
Ex:
|
||||
```shell
|
||||
export PATH="$HOME/.pyenv/bin:$PATH"
|
||||
eval "$(pyenv init -)"
|
||||
eval "$(pyenv virtualenv-init -)"
|
||||
```
|
||||
4. Install version, create virtualenv, activate and install dependencies from inside the `hawk/` directory.
|
||||
**Note** you can simply install dependencies, not create a virtual environment and invoke the script using `poetry run`.
|
||||
|
||||
*Note* You may need to install `python3-venv` for the above to work.
|
||||
```shell
|
||||
$ cd syncstorage-rs/tools/hawk
|
||||
# pyenv version install
|
||||
$ pyenv install 3.10
|
||||
|
||||
Once the virtual env is installed, run `. venv/bin/activate`. This
|
||||
will ensure that calls to python and python tools happen within this
|
||||
virtual environment.
|
||||
# creates named, associated virtualenv
|
||||
$ pyenv virtualenv 3.10 hawk # or whatever project name you like.
|
||||
$ pyenv local hawk # activates virtual env whenever you enter this directory.
|
||||
|
||||
2) install the requirements using:
|
||||
# Install dependencies
|
||||
$ pip install poetry
|
||||
$ poetry install
|
||||
```
|
||||
|
||||
`venv/bin/pip install -r requirements.txt`
|
||||
5. In general, to run the script with the Poetry managed dependencies - once you're already in your virtual env - run the following (more details in #3):
|
||||
`poetry run python make_hawk_token.py`
|
||||
|
||||
3) To create a Token Header:
|
||||
## Create a Token Header:
|
||||
|
||||
You'll need to pass along your `SYNC_MASTER_SECRET` and the uri you'll be testing in order to generate a valid Hawk Id:
|
||||
|
||||
`venv/bin/python make_hawk_token.py --uri /1.5/1/storage/meta/global --secret=$SYNC_MASTER_SECRET --as_header`
|
||||
|
||||
** For testing against uri's using methods other than GET, you'll need to pass along the `--method` flag to generate your token. Ie, `venv/bin/python make_hawk_token.py --method PUT --uri /1.5/1/storage/meta/global --secret=$SYNC_MASTER_SECRET --as_header`. See [examples/put.bash](https://github.com/mozilla-services/syncstorage-rs/blob/master/tools/examples/put.bash) for an example of this.
|
||||
`poetry run python make_hawk_token.py --uri /1.5/1/storage/meta/global --secret=$SYNC_MASTER_SECRET --as_header`
|
||||
|
||||
** For testing against uri's using methods other than GET, you'll need to pass along the `--method` flag to generate your token. Ie, `poetry run python make_hawk_token.py --method PUT --uri /1.5/1/storage/meta/global --secret=$SYNC_MASTER_SECRET --as_header`. See [examples/put.bash](https://github.com/mozilla-services/syncstorage-rs/blob/master/tools/examples/put.bash) for an example of this.
|
||||
|
||||
Use `-h` for help.
|
||||
|
||||
By default, with no passed arguments, a default Hawk Id token will be generated mapping to your localhost:8000 with
|
||||
the path `http://localhost:8000/1.5/1/storage/col2/`.
|
@ -30,7 +30,7 @@ FXA_UID = "DEADBEEF00004be4ae957006c0ceb620"
|
||||
FXA_KID = "DEADBEEF00004be4ae957006c0ceb620"
|
||||
DEVICE_ID = "device1"
|
||||
NODE = "http://localhost:8000"
|
||||
SECRET = os.envrion.get("SYNC_MASTER_SECRET", "Ted_Koppel_is_a_robot")
|
||||
SECRET = os.environ.get("SYNC_MASTER_SECRET", "Ted_Koppel_is_a_robot")
|
||||
HMAC_KEY = b"foo"
|
||||
|
||||
# 10 years
|
||||
|
591
tools/hawk/poetry.lock
generated
Normal file
591
tools/hawk/poetry.lock
generated
Normal file
@ -0,0 +1,591 @@
|
||||
# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "bandit"
|
||||
version = "1.8.6"
|
||||
description = "Security oriented static analyser for python code."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "bandit-1.8.6-py3-none-any.whl", hash = "sha256:3348e934d736fcdb68b6aa4030487097e23a501adf3e7827b63658df464dddd0"},
|
||||
{file = "bandit-1.8.6.tar.gz", hash = "sha256:dbfe9c25fc6961c2078593de55fd19f2559f9e45b99f1272341f5b95dea4e56b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""}
|
||||
PyYAML = ">=5.3.1"
|
||||
rich = "*"
|
||||
stevedore = ">=1.20.0"
|
||||
|
||||
[package.extras]
|
||||
baseline = ["GitPython (>=3.1.30)"]
|
||||
sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"]
|
||||
test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"]
|
||||
toml = ["tomli (>=1.1.0) ; python_version < \"3.11\""]
|
||||
yaml = ["PyYAML"]
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "25.1.0"
|
||||
description = "The uncompromising code formatter."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"},
|
||||
{file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"},
|
||||
{file = "black-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:055e59b198df7ac0b7efca5ad7ff2516bca343276c466be72eb04a3bcc1f82d7"},
|
||||
{file = "black-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:db8ea9917d6f8fc62abd90d944920d95e73c83a5ee3383493e35d271aca872e9"},
|
||||
{file = "black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0"},
|
||||
{file = "black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299"},
|
||||
{file = "black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096"},
|
||||
{file = "black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2"},
|
||||
{file = "black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b"},
|
||||
{file = "black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc"},
|
||||
{file = "black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f"},
|
||||
{file = "black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba"},
|
||||
{file = "black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f"},
|
||||
{file = "black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3"},
|
||||
{file = "black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171"},
|
||||
{file = "black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18"},
|
||||
{file = "black-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1ee0a0c330f7b5130ce0caed9936a904793576ef4d2b98c40835d6a65afa6a0"},
|
||||
{file = "black-25.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3df5f1bf91d36002b0a75389ca8663510cf0531cca8aa5c1ef695b46d98655f"},
|
||||
{file = "black-25.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6827d563a2c820772b32ce8a42828dc6790f095f441beef18f96aa6f8294e"},
|
||||
{file = "black-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:bacabb307dca5ebaf9c118d2d2f6903da0d62c9faa82bd21a33eecc319559355"},
|
||||
{file = "black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717"},
|
||||
{file = "black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=8.0.0"
|
||||
mypy-extensions = ">=0.4.3"
|
||||
packaging = ">=22.0"
|
||||
pathspec = ">=0.9.0"
|
||||
platformdirs = ">=2"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
colorama = ["colorama (>=0.4.3)"]
|
||||
d = ["aiohttp (>=3.10)"]
|
||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||
uvloop = ["uvloop (>=0.15.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.8"
|
||||
description = "Composable command line interface toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
|
||||
{file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
|
||||
]
|
||||
|
||||
[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"
|
||||
groups = ["dev"]
|
||||
markers = "platform_system == \"Windows\""
|
||||
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 = "hawkauthlib"
|
||||
version = "2.0.0"
|
||||
description = "Hawk Access Authentication protocol"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "hawkauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:935878d3a75832aa76f78ddee13491f1466cbd69a8e7e4248902763cf9953ba9"},
|
||||
{file = "hawkauthlib-2.0.0.tar.gz", hash = "sha256:effd64a2572e3c0d9090b55ad2180b36ad50e7760bea225cb6ce2248f421510d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
webob = "*"
|
||||
|
||||
[package.extras]
|
||||
test = ["requests"]
|
||||
|
||||
[[package]]
|
||||
name = "isort"
|
||||
version = "6.0.1"
|
||||
description = "A Python utility / library to sort Python imports."
|
||||
optional = false
|
||||
python-versions = ">=3.9.0"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615"},
|
||||
{file = "isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
colors = ["colorama"]
|
||||
plugins = ["setuptools"]
|
||||
|
||||
[[package]]
|
||||
name = "legacy-cgi"
|
||||
version = "2.6.3"
|
||||
description = "Fork of the standard library cgi and cgitb modules removed in Python 3.13"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
markers = "python_version >= \"3.13\""
|
||||
files = [
|
||||
{file = "legacy_cgi-2.6.3-py3-none-any.whl", hash = "sha256:6df2ea5ae14c71ef6f097f8b6372b44f6685283dc018535a75c924564183cdab"},
|
||||
{file = "legacy_cgi-2.6.3.tar.gz", hash = "sha256:4c119d6cb8e9d8b6ad7cc0ddad880552c62df4029622835d06dfd18f438a8154"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "3.0.0"
|
||||
description = "Python port of markdown-it. Markdown parsing, done right!"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
|
||||
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mdurl = ">=0.1,<1.0"
|
||||
|
||||
[package.extras]
|
||||
benchmarking = ["psutil", "pytest", "pytest-benchmark"]
|
||||
code-style = ["pre-commit (>=3.0,<4.0)"]
|
||||
compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
|
||||
linkify = ["linkify-it-py (>=1,<3)"]
|
||||
plugins = ["mdit-py-plugins"]
|
||||
profiling = ["gprof2dot"]
|
||||
rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
|
||||
testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
description = "Markdown URL utilities"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
|
||||
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.17.0"
|
||||
description = "Optional static typing for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "mypy-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8e08de6138043108b3b18f09d3f817a4783912e48828ab397ecf183135d84d6"},
|
||||
{file = "mypy-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce4a17920ec144647d448fc43725b5873548b1aae6c603225626747ededf582d"},
|
||||
{file = "mypy-1.17.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ff25d151cc057fdddb1cb1881ef36e9c41fa2a5e78d8dd71bee6e4dcd2bc05b"},
|
||||
{file = "mypy-1.17.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93468cf29aa9a132bceb103bd8475f78cacde2b1b9a94fd978d50d4bdf616c9a"},
|
||||
{file = "mypy-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:98189382b310f16343151f65dd7e6867386d3e35f7878c45cfa11383d175d91f"},
|
||||
{file = "mypy-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:c004135a300ab06a045c1c0d8e3f10215e71d7b4f5bb9a42ab80236364429937"},
|
||||
{file = "mypy-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d4fe5c72fd262d9c2c91c1117d16aac555e05f5beb2bae6a755274c6eec42be"},
|
||||
{file = "mypy-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d96b196e5c16f41b4f7736840e8455958e832871990c7ba26bf58175e357ed61"},
|
||||
{file = "mypy-1.17.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73a0ff2dd10337ceb521c080d4147755ee302dcde6e1a913babd59473904615f"},
|
||||
{file = "mypy-1.17.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24cfcc1179c4447854e9e406d3af0f77736d631ec87d31c6281ecd5025df625d"},
|
||||
{file = "mypy-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c56f180ff6430e6373db7a1d569317675b0a451caf5fef6ce4ab365f5f2f6c3"},
|
||||
{file = "mypy-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:eafaf8b9252734400f9b77df98b4eee3d2eecab16104680d51341c75702cad70"},
|
||||
{file = "mypy-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f986f1cab8dbec39ba6e0eaa42d4d3ac6686516a5d3dccd64be095db05ebc6bb"},
|
||||
{file = "mypy-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:51e455a54d199dd6e931cd7ea987d061c2afbaf0960f7f66deef47c90d1b304d"},
|
||||
{file = "mypy-1.17.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3204d773bab5ff4ebbd1f8efa11b498027cd57017c003ae970f310e5b96be8d8"},
|
||||
{file = "mypy-1.17.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1051df7ec0886fa246a530ae917c473491e9a0ba6938cfd0ec2abc1076495c3e"},
|
||||
{file = "mypy-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f773c6d14dcc108a5b141b4456b0871df638eb411a89cd1c0c001fc4a9d08fc8"},
|
||||
{file = "mypy-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:1619a485fd0e9c959b943c7b519ed26b712de3002d7de43154a489a2d0fd817d"},
|
||||
{file = "mypy-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c41aa59211e49d717d92b3bb1238c06d387c9325d3122085113c79118bebb06"},
|
||||
{file = "mypy-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e69db1fb65b3114f98c753e3930a00514f5b68794ba80590eb02090d54a5d4a"},
|
||||
{file = "mypy-1.17.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03ba330b76710f83d6ac500053f7727270b6b8553b0423348ffb3af6f2f7b889"},
|
||||
{file = "mypy-1.17.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037bc0f0b124ce46bfde955c647f3e395c6174476a968c0f22c95a8d2f589bba"},
|
||||
{file = "mypy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c38876106cb6132259683632b287238858bd58de267d80defb6f418e9ee50658"},
|
||||
{file = "mypy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:d30ba01c0f151998f367506fab31c2ac4527e6a7b2690107c7a7f9e3cb419a9c"},
|
||||
{file = "mypy-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:63e751f1b5ab51d6f3d219fe3a2fe4523eaa387d854ad06906c63883fde5b1ab"},
|
||||
{file = "mypy-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fb09d05e0f1c329a36dcd30e27564a3555717cde87301fae4fb542402ddfad"},
|
||||
{file = "mypy-1.17.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b72c34ce05ac3a1361ae2ebb50757fb6e3624032d91488d93544e9f82db0ed6c"},
|
||||
{file = "mypy-1.17.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:434ad499ad8dde8b2f6391ddfa982f41cb07ccda8e3c67781b1bfd4e5f9450a8"},
|
||||
{file = "mypy-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f105f61a5eff52e137fd73bee32958b2add9d9f0a856f17314018646af838e97"},
|
||||
{file = "mypy-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:ba06254a5a22729853209550d80f94e28690d5530c661f9416a68ac097b13fc4"},
|
||||
{file = "mypy-1.17.0-py3-none-any.whl", hash = "sha256:15d9d0018237ab058e5de3d8fce61b6fa72cc59cc78fd91f1b474bce12abf496"},
|
||||
{file = "mypy-1.17.0.tar.gz", hash = "sha256:e5d7ccc08ba089c06e2f5629c660388ef1fee708444f1dee0b9203fa031dee03"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mypy_extensions = ">=1.0.0"
|
||||
pathspec = ">=0.9.0"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
typing_extensions = ">=4.6.0"
|
||||
|
||||
[package.extras]
|
||||
dmypy = ["psutil (>=4.0)"]
|
||||
faster-cache = ["orjson"]
|
||||
install-types = ["pip"]
|
||||
mypyc = ["setuptools (>=50)"]
|
||||
reports = ["lxml"]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.1.0"
|
||||
description = "Type system extensions for programs checked with the mypy type checker."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"},
|
||||
{file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "25.0"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"},
|
||||
{file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.12.1"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
|
||||
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pbr"
|
||||
version = "6.1.1"
|
||||
description = "Python Build Reasonableness"
|
||||
optional = false
|
||||
python-versions = ">=2.6"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76"},
|
||||
{file = "pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
setuptools = "*"
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.3.8"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"},
|
||||
{file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"]
|
||||
type = ["mypy (>=1.14.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "pydocstyle"
|
||||
version = "6.3.0"
|
||||
description = "Python docstring style checker"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"},
|
||||
{file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
snowballstemmer = ">=2.2.0"
|
||||
|
||||
[package.extras]
|
||||
toml = ["tomli (>=1.2.3) ; python_version < \"3.11\""]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.19.2"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"},
|
||||
{file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
windows-terminal = ["colorama (>=0.4.6)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0.2"
|
||||
description = "YAML parser and emitter for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
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 = "rich"
|
||||
version = "14.0.0"
|
||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||
optional = false
|
||||
python-versions = ">=3.8.0"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"},
|
||||
{file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
markdown-it-py = ">=2.2.0"
|
||||
pygments = ">=2.13.0,<3.0.0"
|
||||
typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
jupyter = ["ipywidgets (>=7.5.1,<9)"]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.11.13"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46"},
|
||||
{file = "ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48"},
|
||||
{file = "ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b"},
|
||||
{file = "ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a"},
|
||||
{file = "ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc"},
|
||||
{file = "ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629"},
|
||||
{file = "ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933"},
|
||||
{file = "ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165"},
|
||||
{file = "ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71"},
|
||||
{file = "ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9"},
|
||||
{file = "ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc"},
|
||||
{file = "ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7"},
|
||||
{file = "ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432"},
|
||||
{file = "ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492"},
|
||||
{file = "ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250"},
|
||||
{file = "ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3"},
|
||||
{file = "ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b"},
|
||||
{file = "ruff-0.11.13.tar.gz", hash = "sha256:26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "80.9.0"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"},
|
||||
{file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""]
|
||||
core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "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) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "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) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"]
|
||||
|
||||
[[package]]
|
||||
name = "snowballstemmer"
|
||||
version = "3.0.1"
|
||||
description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"},
|
||||
{file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stevedore"
|
||||
version = "5.4.1"
|
||||
description = "Manage dynamic plugins for Python applications"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "stevedore-5.4.1-py3-none-any.whl", hash = "sha256:d10a31c7b86cba16c1f6e8d15416955fc797052351a56af15e608ad20811fcfe"},
|
||||
{file = "stevedore-5.4.1.tar.gz", hash = "sha256:3135b5ae50fe12816ef291baff420acb727fcd356106e3e9cbfa9e5985cd6f4b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pbr = ">=2.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "tokenlib"
|
||||
version = "2.0.0"
|
||||
description = "Generic library for managing signed authentication tokens."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "tokenlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:1c6de2c06edf54954df535e5bd1cbb6d7821be032102f40e5a8a53acd5b03649"},
|
||||
{file = "tokenlib-2.0.0.tar.gz", hash = "sha256:569f27a117b0e0e6476946c96572741a33449c607835a3c6f3fdac85f93b3408"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.2.1"
|
||||
description = "A lil' TOML parser"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
markers = "python_version < \"3.11\""
|
||||
files = [
|
||||
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
|
||||
{file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
|
||||
{file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
|
||||
{file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
|
||||
{file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
|
||||
{file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.14.1"
|
||||
description = "Backported and Experimental Type Hints for Python 3.9+"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"},
|
||||
{file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webob"
|
||||
version = "1.8.9"
|
||||
description = "WSGI request and response object"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "WebOb-1.8.9-py2.py3-none-any.whl", hash = "sha256:45e34c58ed0c7e2ecd238ffd34432487ff13d9ad459ddfd77895e67abba7c1f9"},
|
||||
{file = "webob-1.8.9.tar.gz", hash = "sha256:ad6078e2edb6766d1334ec3dee072ac6a7f95b1e32ce10def8ff7f0f02d56589"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
legacy-cgi = {version = ">=2.6", markers = "python_version >= \"3.13\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["Sphinx (>=1.7.5)", "pylons-sphinx-themes"]
|
||||
testing = ["coverage", "pytest (>=3.1.0)", "pytest-cov", "pytest-xdist"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.9"
|
||||
content-hash = "d3dacd2c17dd89d0fb9232dfdce6e5c771a9929a0960bccc19ddfacb2a3a1e3b"
|
33
tools/hawk/pyproject.toml
Normal file
33
tools/hawk/pyproject.toml
Normal file
@ -0,0 +1,33 @@
|
||||
[project]
|
||||
name = "hawk"
|
||||
version = "0.1.0"
|
||||
description = "Hawk Compatible Auth Header Utility"
|
||||
authors = [
|
||||
{name = "Taddes",email = "tkorris@mozilla.com"}
|
||||
]
|
||||
license = "Mozilla Public License Version 2.0"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9"
|
||||
|
||||
[tool.poetry]
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
hawkauthlib = "^2.0.0"
|
||||
tokenlib = "^2.0.0"
|
||||
webob = "^1.8.9"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
mypy = "^1.16.0"
|
||||
pydocstyle = "^6.3.0"
|
||||
ruff = "^0.11.13"
|
||||
black = "^25.1.0"
|
||||
bandit = "^1.8.3"
|
||||
isort = "^6.0.1"
|
||||
|
||||
[tool.poetry.requires-plugins]
|
||||
poetry-plugin-export = ">=1.8"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
@ -1,3 +0,0 @@
|
||||
hawkauthlib
|
||||
tokenlib
|
||||
webob
|
1692
tools/integration_tests/poetry.lock
generated
Normal file
1692
tools/integration_tests/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
45
tools/integration_tests/pyproject.toml
Normal file
45
tools/integration_tests/pyproject.toml
Normal file
@ -0,0 +1,45 @@
|
||||
[project]
|
||||
name = "integration-tests"
|
||||
version = "0.1.0"
|
||||
description = "Integration tests for Syncstorage-rs and Tokenserver."
|
||||
authors = [
|
||||
{name = "Taddes",email = "tkorris@mozilla.com"}
|
||||
]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9.2"
|
||||
license = "Mozilla Public License Version 2.0"
|
||||
|
||||
|
||||
[tool.poetry]
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
cryptography = "44.0.2"
|
||||
hawkauthlib = "^2.0.0"
|
||||
konfig = "^1.1"
|
||||
mysqlclient = "^2.2.7"
|
||||
psutil = "^7.0.0"
|
||||
pyjwt = "^2.10.1"
|
||||
pyramid = "^2.0.2"
|
||||
pyramid-hawkauth = "^2.0.0"
|
||||
pyfxa = "0.8.1"
|
||||
pytest = "^8.4.0"
|
||||
requests = "^2.32.4"
|
||||
simplejson = "^3.20.1"
|
||||
sqlalchemy = "1.4.46"
|
||||
tokenlib = "^2.0.0"
|
||||
webtest = "^3.0.6"
|
||||
wsgiproxy2 = "^0.5.1"
|
||||
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
mypy = "^1.16.0"
|
||||
pydocstyle = "^6.3.0"
|
||||
ruff = "^0.11.13"
|
||||
black = "^25.1.0"
|
||||
bandit = "^1.8.3"
|
||||
isort = "^6.0.1"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
0
tools/integration_tests/tokenserver/mock_fxa_server.py
Normal file → Executable file
0
tools/integration_tests/tokenserver/mock_fxa_server.py
Normal file → Executable file
@ -1,8 +1,25 @@
|
||||
FROM python:3.12-bookworm
|
||||
|
||||
COPY purge_ttl.py count_expired_rows.py count_users.py requirements.txt /app/
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PIP_NO_CACHE_DIR=off \
|
||||
PIP_DISABLE_PIP_VERSION_CHECK=on \
|
||||
PIP_DEFAULT_TIMEOUT=100 \
|
||||
POETRY_VERSION=2.1.3 \
|
||||
POETRY_NO_INTERACTION=1 \
|
||||
POETRY_VIRTUALENVS_CREATE=false \
|
||||
POETRY_CACHE_DIR='/var/cache/pypoetry' \
|
||||
POETRY_HOME='/usr/local'
|
||||
|
||||
RUN pip install -r /app/requirements.txt
|
||||
RUN curl -sSL https://install.python-poetry.org | python3 -
|
||||
|
||||
WORKDIR /app/
|
||||
|
||||
COPY purge_ttl.py count_expired_rows.py count_users.py poetry.lock pyproject.toml /app/
|
||||
RUN python3 --version
|
||||
|
||||
RUN poetry config virtualenvs.create false && \
|
||||
poetry install --without dev --no-interaction --no-ansi
|
||||
|
||||
USER nobody
|
||||
|
||||
|
@ -9,3 +9,39 @@ e.g.
|
||||
GOOGLE_APPLICATION_CREDENTIALS=`pwd`/keys/project-id-service-cred.json venv/bin/python purge_ttl.py
|
||||
```
|
||||
See each script for details about function and use.
|
||||
|
||||
## Dependencies and Environment Setup:
|
||||
To use the syncstorage-rs spanner untilities, you'll need a Python =>3.12 development environment with `Poetry` installed. These scripts typically run in a deployed GCP workflow, so their Dockerfile config will generally prepare all of this for you. If you're running them ad-hoc, you'll need to follow these instructions. You can also directly call the script using `Poetry` as described in step 5.
|
||||
|
||||
The easiest solution recommended to use `pyenv` and the `pyenv-virtualenv` plugin for your virtual environments
|
||||
as a way to isolate the dependencies from other directories.
|
||||
1. Install `pyenv` using the [latest documentation](https://github.com/pyenv/pyenv#installation) for your platform.
|
||||
2. Follow the instructions to install the `pyenv-virtualenv` plugin.
|
||||
See the [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv) documentation.
|
||||
3. Ensure you've added `pyenv` and `pyenv-virtualenv` to your PATH.
|
||||
|
||||
Ex:
|
||||
```shell
|
||||
export PATH="$HOME/.pyenv/bin:$PATH"
|
||||
eval "$(pyenv init -)"
|
||||
eval "$(pyenv virtualenv-init -)"
|
||||
```
|
||||
4. Install version, create virtualenv, activate and install dependencies from inside the `spanner/` directory.
|
||||
**Note** you can simply install dependencies, not create a virtual environment and invoke the script using `poetry run`.
|
||||
|
||||
```shell
|
||||
$ cd syncstorage-rs/tools/spanner
|
||||
# pyenv version install
|
||||
$ pyenv install 3.10
|
||||
|
||||
# creates named, associated virtualenv
|
||||
$ pyenv virtualenv 3.10 spanner # or whatever project name you like.
|
||||
$ pyenv local spanner # activates virtual env whenever you enter this directory.
|
||||
|
||||
# Install dependencies
|
||||
$ pip install poetry
|
||||
$ poetry install
|
||||
```
|
||||
|
||||
5. In general, to run the script with the Poetry managed dependencies - once you're already in your virtual env - run the following (more details in #3):
|
||||
Ex. `poetry run python purge_ttl.py`
|
||||
|
1274
tools/spanner/poetry.lock
generated
Normal file
1274
tools/spanner/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
tools/spanner/pyproject.toml
Normal file
32
tools/spanner/pyproject.toml
Normal file
@ -0,0 +1,32 @@
|
||||
[project]
|
||||
name = "spanner"
|
||||
version = "0.1.0"
|
||||
description = "Spanner utility scripts for syncstorage-rs for working with GCP."
|
||||
authors = [
|
||||
{name = "Taddes",email = "tkorris@mozilla.com"}
|
||||
]
|
||||
license = "Mozilla Public License Version 2.0"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9.2"
|
||||
|
||||
[tool.poetry]
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
google-cloud-spanner = ">=1.16.0"
|
||||
statsd = "^4.0.1"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
mypy = "^1.16.0"
|
||||
pydocstyle = "^6.3.0"
|
||||
ruff = "^0.11.13"
|
||||
black = "^25.1.0"
|
||||
bandit = "^1.8.3"
|
||||
isort = "^6.0.1"
|
||||
|
||||
[tool.poetry.requires-plugins]
|
||||
poetry-plugin-export = ">=1.8"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
19
tools/tokenserver/README.md
Normal file
19
tools/tokenserver/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Summary of Files in tools/Tokenserver
|
||||
|
||||
| File Name | Description |
|
||||
|--------------------------------|-----------------------------------------------------------------------------|
|
||||
| `add_node.py` | Adds new node to the tokenserver's database, registering it for user allocation. |
|
||||
| `allocate_user.py` | Script to allocate a specific user to a node. |
|
||||
| `conftest.py` | Pytest configuration and fixtures for shared test setup. |
|
||||
| `count_users.py` | Script to emit total-user-count metrics for exec dashboard. |
|
||||
| `database.py` | Shared database utility queries and functions used by multiple scripts. |
|
||||
| `process_account_events.py` | Script to process account-related events from an SQS queue. |
|
||||
| `purge_old_records.py` | Script to purge user records that have been replaced. |
|
||||
| `pytest.ini` | Configuration file for pytest, specifying options like test output format. |
|
||||
| `remove_node.py` | Script to remove a node from the system. |
|
||||
| `test_database.py` | Unit tests for `database.py`. |
|
||||
| `test_process_account_events.py` | Tests for `process_account_events.py`, ensuring correct behavior for event handling. |
|
||||
| `test_purge_old_records.py` | Tests for `purge_old_records.py`, validating cleanup operations. |
|
||||
| `test_scripts.py` | Testing module to test the various scripts in this directory. |
|
||||
| `unassign_node.py` | Removes a node from the system and clears any assignments to the named node.|
|
||||
| `update_node.py` | Script to update node status in the db. |
|
@ -2,16 +2,60 @@
|
||||
|
||||
This directory contains everything needed to run the suite of load tests for Tokenserver.
|
||||
|
||||
## Prerequisite Dependency and Environment Setup:
|
||||
To use the syncstorage-rs tokenserver load tests, you'll need a Python =>3.12 development environment with `Poetry` installed. This testing script can be run within a spun up GCP workflow where you can execute the locust commands from the UI. If you're running them ad-hoc, you'll need to follow these instructions. You can also directly call the script using `Poetry` as described in step 5.
|
||||
|
||||
The easiest solution recommended to use `pyenv` and the `pyenv-virtualenv` plugin for your virtual environments
|
||||
as a way to isolate the dependencies from other directories.
|
||||
1. Install `pyenv` using the [latest documentation](https://github.com/pyenv/pyenv#installation) for your platform.
|
||||
2. Follow the instructions to install the `pyenv-virtualenv` plugin.
|
||||
See the [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv) documentation.
|
||||
3. Ensure you've added `pyenv` and `pyenv-virtualenv` to your PATH.
|
||||
|
||||
Ex:
|
||||
```shell
|
||||
export PATH="$HOME/.pyenv/bin:$PATH"
|
||||
eval "$(pyenv init -)"
|
||||
eval "$(pyenv virtualenv-init -)"
|
||||
```
|
||||
4. Install version, create virtualenv, activate and install dependencies from inside the `loadtests/` directory.
|
||||
**Note** you can simply install dependencies, not create a virtual environment and invoke the script using `poetry run`.
|
||||
|
||||
```shell
|
||||
$ cd syncstorage-rs/tools/tokenserver/loadtests
|
||||
# pyenv version install
|
||||
$ pyenv install 3.10
|
||||
|
||||
# creates named, associated virtualenv
|
||||
$ pyenv virtualenv 3.10 loadtests # or whatever project name you like.
|
||||
$ pyenv local loadtests # activates virtual env whenever you enter this directory.
|
||||
|
||||
# Install dependencies
|
||||
$ pip install poetry
|
||||
$ poetry install
|
||||
```
|
||||
|
||||
5. In general, to run the script with the Poetry managed dependencies - once you're already in your virtual env - run the following (more details in #3):
|
||||
Ex. `poetry run python locustfile.py`
|
||||
|
||||
|
||||
## Building and Running
|
||||
|
||||
1. Install the load testing dependencies:
|
||||
1. Install the load testing dependencies as described above:
|
||||
|
||||
```sh
|
||||
pip3 install -r requirements.txt
|
||||
poetry install
|
||||
```
|
||||
|
||||
1. Run the `generate-keys.sh` script to generate an RSA keypair and derive the public JWK:
|
||||
2. Run the `generate-keys.sh` script to generate an RSA keypair and derive the public JWK.
|
||||
Since this script calls `get_jwk.py` and it has a dependency on `autlib`, call the shell script using Poetry:
|
||||
|
||||
```sh
|
||||
poetry run ./generate-keys.sh
|
||||
```
|
||||
|
||||
Otherwise, if in built virtual environment with installed Poetry dependencies:
|
||||
|
||||
```sh
|
||||
./generate-keys.sh
|
||||
```
|
||||
@ -29,7 +73,7 @@ This directory contains everything needed to run the suite of load tests for Tok
|
||||
}
|
||||
```
|
||||
|
||||
1. Set the following environment variables/settings on Tokenserver:
|
||||
3. Set the following environment variables/settings on Tokenserver:
|
||||
|
||||
```sh
|
||||
# Should be set to the "n" component of the JWK
|
||||
@ -45,7 +89,7 @@ This directory contains everything needed to run the suite of load tests for Tok
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK_FXA_CREATED_AT=0
|
||||
```
|
||||
|
||||
1. Configure Tokenserver to verify BrowserID assertions through FxA stage. This is done by setting the following environment variables:
|
||||
4. Configure Tokenserver to verify BrowserID assertions through FxA stage. This is done by setting the following environment variables:
|
||||
|
||||
```sh
|
||||
# The exact value of this environment variable is not important as long as it matches the `BROWSERID_AUDIENCE` environment variable set on the machine running the load tests, as described below
|
||||
@ -57,29 +101,34 @@ This directory contains everything needed to run the suite of load tests for Tok
|
||||
|
||||
Note that, because we have cached the JWK used to verify OAuth tokens, no verification requests will be made to FxA, so the value of `SYNC_TOKENSERVER__FXA_OAUTH_VERIFIER_URL` does not matter; however, Tokenserver expects it to be set, so setting it to something like `http://localhost` will suffice.
|
||||
|
||||
1. Set the following environment variables on the machine that will be running the load tests:
|
||||
5. Set the following environment variables on the machine that will be running the load tests:
|
||||
|
||||
- `OAUTH_PEM_FILE` should be set to the location of the private RSA key generated in a previous step
|
||||
- `BROWSERID_AUDIENCE` should be set to match the `SYNC_TOKENSERVER__FXA_BROWSERID_AUDIENCE` environment variable on Tokenserver
|
||||
|
||||
1. Tokenserver uses [locust](https://locust.io/) for load testing. To run the load tests, simply run the following command in this directory:
|
||||
6. Tokenserver uses [locust](https://locust.io/) for load testing. To run the load tests, simply run the following command in this directory:
|
||||
|
||||
```sh
|
||||
locust
|
||||
```
|
||||
|
||||
1. Navigate your browser to <http://localhost:8090>, where you'll find the locust GUI. Enter the following information:
|
||||
7. Navigate your browser to <http://localhost:8090>, where you'll find the locust GUI. Enter the following information:
|
||||
|
||||
- Number of users: The peak number of Tokenserver users to be used during the load tests
|
||||
- Spawn rate: The rate at which new users are spawned
|
||||
- Host: The URL of the server to be load tested. Note that this URL must include the protocol (e.g. "http://")
|
||||
|
||||
1. Click the "Start swarming" button to begin the load tests.
|
||||
8. Click the "Start swarming" button to begin the load tests.
|
||||
|
||||
## Populating the Database
|
||||
|
||||
This directory includes an optional `populate_db.py` script that can be used to add test users to the database en masse. The script can be run like so:
|
||||
|
||||
```sh
|
||||
poetry run python populate_db.py <sqlurl> <nodes> <number of users>
|
||||
```
|
||||
|
||||
Or if in built virtualenv:
|
||||
```sh
|
||||
python3 populate_db.py <sqlurl> <nodes> <number of users>
|
||||
```
|
||||
|
2028
tools/tokenserver/loadtests/poetry.lock
generated
Normal file
2028
tools/tokenserver/loadtests/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
tools/tokenserver/loadtests/pyproject.toml
Normal file
37
tools/tokenserver/loadtests/pyproject.toml
Normal file
@ -0,0 +1,37 @@
|
||||
[project]
|
||||
name = "tokenserver-load-tests"
|
||||
version = "0.1.0"
|
||||
description = "tokenserver load tests"
|
||||
authors = [
|
||||
{name = "Taddes",email = "tkorris@mozilla.com"}
|
||||
]
|
||||
license = "Mozilla Public License Version 2.0"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10,<3.12"
|
||||
|
||||
|
||||
[tool.poetry]
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
authlib = "^1.6.0"
|
||||
cryptography = "^45.0.4"
|
||||
locust = "^2.37.10"
|
||||
pybrowserid = "^0.14.0"
|
||||
pyjwt = "^2.10.1"
|
||||
sqlalchemy = "^2.0.41"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
mypy = "^1.16.0"
|
||||
pydocstyle = "^6.3.0"
|
||||
ruff = "^0.11.13"
|
||||
black = "^25.1.0"
|
||||
bandit = "^1.8.3"
|
||||
isort = "^6.0.1"
|
||||
|
||||
[tool.poetry.requires-plugins]
|
||||
poetry-plugin-export = ">=1.8"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
1263
tools/tokenserver/poetry.lock
generated
Normal file
1263
tools/tokenserver/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
42
tools/tokenserver/pyproject.toml
Normal file
42
tools/tokenserver/pyproject.toml
Normal file
@ -0,0 +1,42 @@
|
||||
[project]
|
||||
name = "tokenserver"
|
||||
version = "0.1.0"
|
||||
description = "Tokenserver utilites, scripts, and tests"
|
||||
authors = [
|
||||
{name = "Taddes",email = "tkorris@mozilla.com"}
|
||||
]
|
||||
readme = "README.md"
|
||||
# Odd <4.0 designation required for backoff dependency.
|
||||
requires-python = ">=3.9.2,<4.0"
|
||||
license = "Mozilla Public License Version 2.0"
|
||||
|
||||
[tool.poetry]
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
boto = "2.49.0"
|
||||
hawkauthlib = "2.0.0"
|
||||
mysqlclient = "2.1.1"
|
||||
pyramid = "2.0.2"
|
||||
sqlalchemy = "1.4.46"
|
||||
testfixtures = "^8.3.0"
|
||||
tokenlib = "2.0.0"
|
||||
pybrowserid = "0.14.0"
|
||||
pytest = "8.3.5"
|
||||
backoff = "^2.2.1"
|
||||
datadog = "^0.51.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
mypy = "^1.16.0"
|
||||
pydocstyle = "^6.3.0"
|
||||
ruff = "^0.11.13"
|
||||
black = "^25.1.0"
|
||||
bandit = "^1.8.3"
|
||||
isort = "^6.0.1"
|
||||
|
||||
[tool.poetry.requires-plugins]
|
||||
poetry-plugin-export = ">=1.8"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
Loading…
Reference in New Issue
Block a user