diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5719ee2d16..107cf6a43f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,8 @@ Changelog in development -------------- +* Added support for gevent to replace eventlet. Going forward, the default will be gevent, and can be overriden in the conf file `system.concurrency_library = gevent|eventlet` @jzufelt #6372 + * implemented zstandard compression for parameters and results. #5995 contributed by @guzzijones12 diff --git a/Makefile b/Makefile index a8c4d9846e..e964c91765 100644 --- a/Makefile +++ b/Makefile @@ -184,12 +184,6 @@ install-runners: @echo "" # NOTE: We use xargs to speed things up by installing runners in parallel echo -e "$(COMPONENTS_RUNNERS)" | tr -d "\n" | xargs -P $(XARGS_CONCURRENCY) -d " " -n1 -i bash -c "set -x; . $(VIRTUALENV_DIR)/bin/activate; cd $$(pwd)/{} ; $(PYBIN) -m pip install --editable . --no-deps" - #@for component in $(COMPONENTS_RUNNERS); do \ - # echo "==========================================================="; \ - # echo "Installing runner:" $$component; \ - # echo "==========================================================="; \ - # #(. $(VIRTUALENV_DIR)/bin/activate; cd $$component; python -m pip install --editable . --no-deps); \ - #done .PHONY: install-mock-runners install-mock-runners: @@ -198,12 +192,6 @@ install-mock-runners: @echo "" # NOTE: We use xargs to speed things up by installing runners in parallel echo -e "$(MOCK_RUNNERS)" | tr -d "\n" | xargs -P $(XARGS_CONCURRENCY) -d " " -n1 -i sh -c ". $(VIRTUALENV_DIR)/bin/activate; cd $$(pwd)/{} ; $(PYBIN) -m pip install --editable . --no-deps" - #@for component in $(MOCK_RUNNERS); do \ - # echo "==========================================================="; \ - # echo "Installing mock runner:" $$component; \ - # echo "==========================================================="; \ - # (. $(VIRTUALENV_DIR)/bin/activate; cd $$component; python -m pip install --editable . --no-deps); \ - #done .PHONY: check-requirements .check-requirements: @@ -262,12 +250,12 @@ check-python-packages: @echo "================== CHECK PYTHON PACKAGES ====================" @echo "" test -f $(VIRTUALENV_COMPONENTS_DIR)/bin/activate || $(PYBIN) -m venv $(VIRTUALENV_COMPONENTS_DIR) --system-site-packages - $(VIRTUALENV_COMPONENTS_DIR)/bin/pip install --quiet "setuptools==$(SETUPTOOLS_VERSION)" + $(VIRTUALENV_COMPONENTS_DIR)/bin/pip install --quiet "setuptools==$(SETUPTOOLS_VERSION)" setuptools_scm @for component in $(COMPONENTS_WITHOUT_ST2TESTS); do \ echo "==========================================================="; \ echo "Checking component:" $$component; \ echo "==========================================================="; \ - (set -e; cd $$component; ../$(VIRTUALENV_COMPONENTS_DIR)/bin/$(PYBIN) setup.py --version) || exit 1; \ + (set -e; cd $$component; ../$(VIRTUALENV_COMPONENTS_DIR)/bin/$(PYBIN) -m setuptools_scm) || exit 1; \ done .PHONY: check-python-packages-nightly @@ -279,13 +267,13 @@ check-python-packages-nightly: @echo "" test -f $(VIRTUALENV_COMPONENTS_DIR)/bin/activate || $(PYBIN) -m venv $(VIRTUALENV_COMPONENTS_DIR) --system-site-packages - $(VIRTUALENV_COMPONENTS_DIR)/bin/pip install --quiet "setuptools==$(SETUPTOOLS_VERSION)" wheel + $(VIRTUALENV_COMPONENTS_DIR)/bin/pip install --quiet "setuptools==$(SETUPTOOLS_VERSION)" setuptools_scm wheel @for component in $(COMPONENTS_WITHOUT_ST2TESTS); do \ echo "==========================================================="; \ echo "Checking component:" $$component; \ echo "==========================================================="; \ - (set -e; cd $$component; ../$(VIRTUALENV_COMPONENTS_DIR)/bin/$(PYBIN) setup.py --version) || exit 1; \ - (set -e; cd $$component; ../$(VIRTUALENV_COMPONENTS_DIR)/bin/$(PYBIN) setup.py sdist bdist_wheel) || exit 1; \ + (set -e; cd $$component; ../$(VIRTUALENV_COMPONENTS_DIR)/bin/$(PYBIN) -m setuptools_scm) || exit 1; \ + (set -e; cd $$component; ../$(VIRTUALENV_COMPONENTS_DIR)/bin/$(PYBIN) -m build) || exit 1; \ (set -e; cd $$component; ../$(VIRTUALENV_COMPONENTS_DIR)/bin/$(PYBIN) -m pip install --editable . --no-deps) || exit 1; \ ($(VIRTUALENV_COMPONENTS_DIR)/bin/$(PYBIN) -c "import $$component") || exit 1; \ (set -e; cd $$component; rm -rf dist/; rm -rf $$component.egg-info) || exit 1; \ @@ -662,13 +650,6 @@ distclean: clean scripts/write-headers.sh $$component/dist_utils.py || break;\ done - # Copy over CHANGELOG.RST, CONTRIBUTING.RST and LICENSE file to each component directory - #@for component in $(COMPONENTS_TEST); do\ - # test -s $$component/README.rst || cp -f README.rst $$component/; \ - # cp -f CONTRIBUTING.rst $$component/; \ - # cp -f LICENSE $$component/; \ - #done - .PHONY: .requirements .requirements: virtualenv $(VIRTUALENV_DIR)/bin/$(PYBIN) -m pip install --upgrade "pip==$(PIP_VERSION)" @@ -681,16 +662,10 @@ distclean: clean # Remove any *.egg-info files which polute PYTHONPATH rm -rf *.egg-info* - # Generate finall requirements.txt file for each component + # Generate final requirements.txt file for each component # NOTE: We use xargs to speed things up by running commands in parallel echo -e "$(COMPONENTS_WITH_RUNNERS)" | tr -d "\n" | xargs -P $(XARGS_CONCURRENCY) -d " " -n1 -i sh -c "$(VIRTUALENV_DIR)/bin/$(PYBIN) scripts/fixate-requirements.py --skip=virtualenv,virtualenv-osx -s {}/in-requirements.txt -f fixed-requirements.txt -o {}/requirements.txt" - #@for component in $(COMPONENTS_WITH_RUNNERS); do\ - # echo "==========================================================="; \ - # echo "Generating requirements.txt for" $$component; \ - # $(VIRTUALENV_DIR)/bin/python scripts/fixate-requirements.py --skip=virtualenv,virtualenv-osx -s $$component/in-requirements.txt -f fixed-requirements.txt -o $$component/requirements.txt; \ - #done - @echo "===========================================================" .PHONY: requirements @@ -781,21 +756,6 @@ endif echo 'export PYTHONPATH' >> $(VIRTUALENV_DIR)/bin/activate touch $(VIRTUALENV_DIR)/bin/activate - # Setup PYTHONPATH in fish activate script... - #echo '' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo 'set -gx _OLD_PYTHONPATH $$PYTHONPATH' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo 'set -gx PYTHONPATH $$_OLD_PYTHONPATH $(COMPONENT_PYTHONPATH)' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo 'functions -c deactivate old_deactivate' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo 'function deactivate' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo ' if test -n $$_OLD_PYTHONPATH' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo ' set -gx PYTHONPATH $$_OLD_PYTHONPATH' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo ' set -e _OLD_PYTHONPATH' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo ' end' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo ' old_deactivate' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo ' functions -e old_deactivate' >> $(VIRTUALENV_DIR)/bin/activate.fish - #echo 'end' >> $(VIRTUALENV_DIR)/bin/activate.fish - #touch $(VIRTUALENV_DIR)/bin/activate.fish - # debug pip installed packages $(VIRTUALENV_DIR)/bin/pip list @@ -867,7 +827,7 @@ endif @echo @echo "----- Dropping st2-test db -----" @mongosh st2-test --eval "db.dropDatabase();" - failed=0; \ + failed=(); \ for component in $(COMPONENTS_TEST); do\ echo "==========================================================="; \ echo "Running tests in" $$component; \ @@ -878,13 +838,13 @@ endif ST2TESTS_REDIS_PORT=$(ST2TESTS_REDIS_PORT) \ COVERAGE_FILE=.coverage.unit.$$(echo $$component | tr '/' '.') \ pytest --verbose $(PYTEST_OPTS) --cov=$$component --cov-branch \ - $$component/tests/unit || ((failed+=1)); \ + $$component/tests/unit || failed+=($$component); \ echo "-----------------------------------------------------------"; \ echo "Done running tests in" $$component; \ echo "==========================================================="; \ done; \ - echo pytest runs failed=$$failed; \ - if [ $$failed -gt 0 ]; then exit 1; fi + echo "pytest runs failed=$${failed[@]}"; \ + if [ $${#failed[@]} -gt 0 ]; then exit 1; fi .PHONY: .combine-unit-tests-coverage .combine-unit-tests-coverage: .run-unit-tests-coverage @@ -929,7 +889,7 @@ itests: requirements .itests @echo @echo "----- Dropping st2-test db -----" @mongosh st2-test --eval "db.dropDatabase();" - @failed=0; \ + @failed=(); \ for component in $(COMPONENTS_TEST); do\ echo "==========================================================="; \ echo "Running integration tests in" $$component; \ @@ -937,13 +897,13 @@ itests: requirements .itests . $(VIRTUALENV_DIR)/bin/activate; \ EVENTLET_TESTS=1 \ pytest --capture=no --verbose $(PYTEST_OPTS) \ - $$component/tests/integration || ((failed+=1)); \ + $$component/tests/integration || failed+=($$component); \ echo "-----------------------------------------------------------"; \ echo "Done running integration tests in" $$component; \ echo "==========================================================="; \ done; \ - echo pytest runs failed=$$failed; \ - if [ $$failed -gt 0 ]; then exit 1; fi + echo "pytest runs failed=$${failed[@]}"; \ + if [ $${#failed[@]} -gt 0 ]; then exit 1; fi .PHONY: .run-integration-tests-coverage ifdef INCLUDE_TESTS_IN_COVERAGE @@ -955,7 +915,7 @@ endif @echo @echo "----- Dropping st2-test db -----" @mongosh st2-test --eval "db.dropDatabase();" - @failed=0; \ + @failed=(); \ for component in $(COMPONENTS_TEST); do\ echo "==========================================================="; \ echo "Running integration tests in" $$component; \ @@ -964,13 +924,13 @@ endif EVENTLET_TESTS=1 \ COVERAGE_FILE=.coverage.integration.$$(echo $$component | tr '/' '.') \ pytest --capture=no --verbose $(PYTEST_OPTS) --cov=$$component --cov-branch \ - $$component/tests/integration || ((failed+=1)); \ + $$component/tests/integration || failed+=($$component); \ echo "-----------------------------------------------------------"; \ echo "Done integration running tests in" $$component; \ echo "==========================================================="; \ done; \ - echo pytest runs failed=$$failed; \ - if [ $$failed -gt 0 ]; then exit 1; fi + echo "pytest runs failed=$${failed[@]}"; \ + if [ $${#failed[@]} -gt 0 ]; then exit 1; fi # NOTE: If you also want to run orquesta tests which seem to have a bunch of race conditions, use # ci-integration-full target # @echo @@ -1039,13 +999,6 @@ endif make .coverage-combine; \ fi -# @for coverage_result in $(COVERAGE_GLOBS); do \ -# [ -e $${coverage_result} ] || echo "$${coverage_result} does not exist." && continue; \ -# echo "Combining data from $${coverage_result}"; \ -# . $(VIRTUALENV_DIR)/bin/activate; coverage combine $${coverage_result}; \ -# done || \ -# (echo "Running .coverage-combine"; make .coverage-combine) - .PHONY: .coverage-report .coverage-report: .coverage . $(VIRTUALENV_DIR)/bin/activate; coverage report @@ -1096,14 +1049,16 @@ runners-tests: requirements .runners-tests @echo @echo "----- Dropping st2-test db -----" @mongosh st2-test --eval "db.dropDatabase();" - @failed=0; \ + @failed=(); \ for component in $(COMPONENTS_RUNNERS); do\ echo "==========================================================="; \ echo "Running tests in" $$component; \ echo "==========================================================="; \ - . $(VIRTUALENV_DIR)/bin/activate; pytest --capture=no --verbose $(PYTEST_OPTS) $$component/tests/unit || ((failed+=1)); \ + . $(VIRTUALENV_DIR)/bin/activate; \ + pytest --capture=no --verbose $(PYTEST_OPTS) $$component/tests/unit || failed+=($$component); \ done; \ - if [ $$failed -gt 0 ]; then exit 1; fi + echo "pytest runs failed=$${failed[@]}"; \ + if [ $${#failed[@]} -gt 0 ]; then exit 1; fi .PHONY: runners-itests runners-itests: requirements .runners-itests @@ -1114,15 +1069,16 @@ runners-itests: requirements .runners-itests @echo "==================== runners-itests ====================" @echo @echo "----- Dropping st2-test db -----" - @failed=0; \ + @failed=(); \ for component in $(COMPONENTS_RUNNERS); do\ echo "==========================================================="; \ echo "Running integration tests in" $$component; \ echo "==========================================================="; \ - . $(VIRTUALENV_DIR)/bin/activate; pytest --capture=no --verbose $(PYTEST_OPTS) $$component/tests/integration || ((failed+=1)); \ + . $(VIRTUALENV_DIR)/bin/activate; \ + pytest --capture=no --verbose $(PYTEST_OPTS) $$component/tests/integration || failed+=($$component); \ done; \ - echo pytest runs failed=$$failed; \ - if [ $$failed -gt 0 ]; then exit 1; fi + echo "pytest runs failed=$${failed[@]}"; \ + if [ $${#failed[@]} -gt 0 ]; then exit 1; fi .PHONY: .runners-itests-coverage-html .runners-itests-coverage-html: @@ -1130,16 +1086,16 @@ runners-itests: requirements .runners-itests @echo "============== runners-itests-coverage-html ==============" @echo @echo "The tests assume st2 is running on 127.0.0.1." - @failed=0; \ + @failed=(); \ for component in $(COMPONENTS_RUNNERS); do\ echo "==========================================================="; \ echo "Running integration tests in" $$component; \ echo "==========================================================="; \ . $(VIRTUALENV_DIR)/bin/activate; pytest --capture=no --verbose $(PYTEST_OPTS) \ - --cov=$$component --cov-report=html $$component/tests/integration || ((failed+=1)); \ + --cov=$$component --cov-report=html $$component/tests/integration || failed+=($$component); \ done; \ - echo pytest runs failed=$$failed; \ - if [ $$failed -gt 0 ]; then exit 1; fi + echo "pytest runs failed=$${failed[@]}"; \ + if [ $${#failed[@]} -gt 0 ]; then exit 1; fi .PHONY: cli cli: diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index 27a2eb0a86..150fd1133c 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -352,6 +352,9 @@ protocol = udp [system] # Base path to all st2 artifacts. base_path = /opt/stackstorm +# Green thread concurrency library to use ('eventlet' or 'gevent'). NOTE: This is read directly from this config file at process startup, before oslo_config is available, so it cannot be overridden via CLI args or environment variables. +# Valid values: eventlet, gevent +concurrency_library = gevent # Enable debug mode. debug = False # True to validate action and runner output against schema. diff --git a/conf/st2.tests.conf b/conf/st2.tests.conf index d4301d0433..82b5b574e0 100644 --- a/conf/st2.tests.conf +++ b/conf/st2.tests.conf @@ -44,6 +44,7 @@ api_url = http://127.0.0.1:9101/ [system] # This way integration tests can write to this directory base_path = /tmp +concurrency_library = gevent [garbagecollector] logging = st2reactor/conf/logging.garbagecollector.conf diff --git a/conftest.py b/conftest.py index 8bfc45b048..c112ab1f81 100644 --- a/conftest.py +++ b/conftest.py @@ -14,6 +14,16 @@ import hashlib from typing import Iterable, List, Sequence +# NOTE: This must happen before any test module imports anything that pulls in tooz/eventlet +# (e.g. st2common.services.coordination). Tooz's Heart binds threading.Thread/Event as default +# args at import time, so if it's imported before monkey patching, it permanently uses the +# unpatched primitives -- causing gevent.exceptions.LoopExit or hangs later. Pytest always loads +# this file before any test module, in both whole-directory and single-file (Pants) runs, so this +# is the one place that reliably wins the race regardless of which test file happens to run first. +from st2common.util.monkey_patch import monkey_patch + +monkey_patch() + from _pytest import nodes from _pytest.config import create_terminal_writer diff --git a/contrib/examples/actions/python-mock-create-vm.py b/contrib/examples/actions/python-mock-create-vm.py index 788a7d11df..3cfb50b4e5 100644 --- a/contrib/examples/actions/python-mock-create-vm.py +++ b/contrib/examples/actions/python-mock-create-vm.py @@ -13,15 +13,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -import eventlet import random from st2common.runners.base_action import Action +from st2common.util import concurrency class MockCreateVMAction(Action): def run(self, cpu_cores, memory_mb, vm_name, ip): - eventlet.sleep(5) + concurrency.sleep(5) data = { "vm_id": "vm" + str(random.randint(0, 10000)), diff --git a/contrib/hello_st2/sensors/sensor1.py b/contrib/hello_st2/sensors/sensor1.py index 1bc534bf69..ba119ad720 100644 --- a/contrib/hello_st2/sensors/sensor1.py +++ b/contrib/hello_st2/sensors/sensor1.py @@ -13,8 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import eventlet - +from st2common.util import concurrency from st2reactor.sensor.base import Sensor @@ -34,7 +33,7 @@ def run(self): payload = {"greeting": "Yo, StackStorm!", "count": int(count) + 1} self.sensor_service.dispatch(trigger="hello_st2.event1", payload=payload) self.sensor_service.set_value("hello_st2.count", payload["count"]) - eventlet.sleep(60) + concurrency.sleep(60) def cleanup(self): self._stop = True diff --git a/contrib/runners/action_chain_runner/action_chain_runner/action_chain_runner.py b/contrib/runners/action_chain_runner/action_chain_runner/action_chain_runner.py index b923a38c20..5b336d16a5 100644 --- a/contrib/runners/action_chain_runner/action_chain_runner/action_chain_runner.py +++ b/contrib/runners/action_chain_runner/action_chain_runner/action_chain_runner.py @@ -15,7 +15,6 @@ from __future__ import absolute_import -import eventlet import traceback import uuid import datetime @@ -24,6 +23,7 @@ from jsonschema import exceptions as json_schema_exc from oslo_config import cfg +from st2common.util import concurrency from st2common.runners.base import ActionRunner from st2common.runners.base import get_metadata as get_runner_metadata from st2common import log as logging @@ -879,7 +879,7 @@ def _run_action(self, liveaction, wait_for_completion=True, sleep_delay=1.0): action_constants.LIVEACTION_STATUS_PENDING, ] ): - eventlet.sleep(sleep_delay) + concurrency.sleep(sleep_delay) liveaction = action_db_util.get_liveaction_by_id(liveaction.id) return liveaction @@ -901,7 +901,7 @@ def _resume_action(self, liveaction, wait_for_completion=True, sleep_delay=1.0): action_constants.LIVEACTION_COMPLETED_STATES + [action_constants.LIVEACTION_STATUS_PAUSED] ): - eventlet.sleep(sleep_delay) + concurrency.sleep(sleep_delay) liveaction = action_db_util.get_liveaction_by_id(liveaction.id) return liveaction diff --git a/contrib/runners/action_chain_runner/tests/unit/test_actionchain.py b/contrib/runners/action_chain_runner/tests/unit/test_actionchain.py index 953b2d6acb..ffd3aae35b 100644 --- a/contrib/runners/action_chain_runner/tests/unit/test_actionchain.py +++ b/contrib/runners/action_chain_runner/tests/unit/test_actionchain.py @@ -368,7 +368,7 @@ def test_chain_runner_bad_default(self, request): runnerexceptions.ActionRunnerPreRunError, expected_msg, chain_runner.pre_run ) - @mock.patch("eventlet.sleep", mock.MagicMock()) + @mock.patch("st2common.util.concurrency.sleep", mock.MagicMock()) @mock.patch.object( action_db_util, "get_liveaction_by_id", diff --git a/contrib/runners/action_chain_runner/tests/unit/test_actionchain_cancel.py b/contrib/runners/action_chain_runner/tests/unit/test_actionchain_cancel.py index e04d5c01b1..6a15db1ced 100644 --- a/contrib/runners/action_chain_runner/tests/unit/test_actionchain_cancel.py +++ b/contrib/runners/action_chain_runner/tests/unit/test_actionchain_cancel.py @@ -14,8 +14,9 @@ # limitations under the License. from __future__ import absolute_import -import eventlet import mock + +from st2common.util import concurrency import os import tempfile @@ -98,7 +99,7 @@ def _wait_for_children(self, execution, interval=0.1, retries=100): for i in range(0, retries): execution = ActionExecution.get_by_id(str(execution.id)) if len(getattr(execution, "children", [])) <= 0: - eventlet.sleep(interval) + concurrency.sleep(interval) continue return execution diff --git a/contrib/runners/action_chain_runner/tests/unit/test_actionchain_notifications.py b/contrib/runners/action_chain_runner/tests/unit/test_actionchain_notifications.py index df1c1567d9..880225e607 100644 --- a/contrib/runners/action_chain_runner/tests/unit/test_actionchain_notifications.py +++ b/contrib/runners/action_chain_runner/tests/unit/test_actionchain_notifications.py @@ -14,9 +14,10 @@ # limitations under the License. from __future__ import absolute_import -import eventlet import mock +from st2common.util import concurrency + from st2common.bootstrap import actionsregistrar from st2common.bootstrap import runnersregistrar from st2common.constants import action as action_constants @@ -221,7 +222,7 @@ def _wait_for_children( % (expected_children, found_children) ) - eventlet.sleep(interval) + concurrency.sleep(interval) found_children = len(getattr(execution, "children", [])) diff --git a/contrib/runners/action_chain_runner/tests/unit/test_actionchain_pause_resume.py b/contrib/runners/action_chain_runner/tests/unit/test_actionchain_pause_resume.py index 6187522d42..412b570bbe 100644 --- a/contrib/runners/action_chain_runner/tests/unit/test_actionchain_pause_resume.py +++ b/contrib/runners/action_chain_runner/tests/unit/test_actionchain_pause_resume.py @@ -14,8 +14,9 @@ # limitations under the License. from __future__ import absolute_import -import eventlet import mock + +from st2common.util import concurrency import os import tempfile @@ -120,7 +121,7 @@ def _wait_for_status(self, liveaction, status, interval=0.1, retries=100): for i in range(0, retries): liveaction = LiveAction.get_by_id(str(liveaction.id)) if liveaction.status != status: - eventlet.sleep(interval) + concurrency.sleep(interval) continue else: break @@ -132,7 +133,7 @@ def _wait_for_children(self, execution, interval=0.1, retries=100): for i in range(0, retries): execution = ActionExecution.get_by_id(str(execution.id)) if len(getattr(execution, "children", [])) <= 0: - eventlet.sleep(interval) + concurrency.sleep(interval) continue return execution diff --git a/contrib/runners/local_runner/tests/integration/test_localrunner.py b/contrib/runners/local_runner/tests/integration/test_localrunner.py index f165a72ff3..68cf6a303d 100644 --- a/contrib/runners/local_runner/tests/integration/test_localrunner.py +++ b/contrib/runners/local_runner/tests/integration/test_localrunner.py @@ -35,7 +35,7 @@ from st2common.constants.runners import LOCAL_RUNNER_DEFAULT_ACTION_TIMEOUT from st2tests.base import RunnerTestCase from st2tests.base import CleanDbTestCase -from st2tests.base import blocking_eventlet_spawn +from st2tests.base import blocking_concurrency_spawn from st2tests.base import make_mock_stream_readline from st2tests.fixtures.generic.fixture import PACK_NAME as GENERIC_PACK from st2tests.fixtures.localrunner_pack.fixture import PACK_NAME as LOCALRUNNER_PACK @@ -181,7 +181,7 @@ def test_action_stdout_and_stderr_is_stored_in_the_db(self, mock_spawn, mock_pop # Note: We need to mock spawn function so we can test everything in single event loop # iteration - mock_spawn.side_effect = blocking_eventlet_spawn + mock_spawn.side_effect = blocking_concurrency_spawn # No output to stdout and no result (implicit None) mock_stdout = [ @@ -249,7 +249,7 @@ def test_action_stdout_and_stderr_is_stored_in_the_db_short_running_action( # Note: We need to mock spawn function so we can test everything in single event loop # iteration - mock_spawn.side_effect = blocking_eventlet_spawn + mock_spawn.side_effect = blocking_concurrency_spawn # No output to stdout and no result (implicit None) mock_stdout = ["stdout line 1\n", "stdout line 2\n"] @@ -553,7 +553,7 @@ def test_action_stdout_and_stderr_is_stored_in_the_db(self, mock_spawn, mock_pop # Note: We need to mock spawn function so we can test everything in single event loop # iteration - mock_spawn.side_effect = blocking_eventlet_spawn + mock_spawn.side_effect = blocking_concurrency_spawn # No output to stdout and no result (implicit None) mock_stdout = [ diff --git a/contrib/runners/python_runner/tests/unit/test_pythonrunner.py b/contrib/runners/python_runner/tests/unit/test_pythonrunner.py index f66d6f8f50..a75974cf51 100644 --- a/contrib/runners/python_runner/tests/unit/test_pythonrunner.py +++ b/contrib/runners/python_runner/tests/unit/test_pythonrunner.py @@ -41,7 +41,7 @@ from python_runner.python_action_wrapper import PythonActionWrapper from st2tests.base import RunnerTestCase from st2tests.base import CleanDbTestCase -from st2tests.base import blocking_eventlet_spawn +from st2tests.base import blocking_concurrency_spawn from st2tests.base import make_mock_stream_readline from st2tests.fixtures.packs.dummy_pack_1.fixture import PACK_NAME as DUMMY_PACK_1 from st2tests.fixtures.packs.dummy_pack_5.fixture import PACK_NAME as DUMMY_PACK_5 @@ -322,7 +322,7 @@ def test_action_stdout_and_stderr_is_not_stored_in_db_by_default( # Note: We need to mock spawn function so we can test everything in single event loop # iteration - mock_spawn.side_effect = blocking_eventlet_spawn + mock_spawn.side_effect = blocking_concurrency_spawn # No output to stdout and no result (implicit None) mock_stdout = [ @@ -403,7 +403,7 @@ def test_action_stdout_and_stderr_is_stored_in_the_db(self, mock_spawn, mock_pop # Note: We need to mock spawn function so we can test everything in single event loop # iteration - mock_spawn.side_effect = blocking_eventlet_spawn + mock_spawn.side_effect = blocking_concurrency_spawn # No output to stdout and no result (implicit None) mock_stdout = [ diff --git a/fixed-requirements.txt b/fixed-requirements.txt index 81b1798e56..495efb8e7a 100644 --- a/fixed-requirements.txt +++ b/fixed-requirements.txt @@ -7,87 +7,87 @@ # ---------------------------------------------------------------------- # Note: amqp is used by kombu amqp==5.3.1 -apscheduler==3.11.0 -chardet==5.2.0 -cffi==1.17.1 -cryptography==43.0.3 -# Gunicorn <26 requires eventlet>=0.40.3 -eventlet==0.40.3 +apscheduler==3.11.3 +chardet==7.6.0 +cffi==2.1.1 +# range (not ==) so lockfiles_to_reqs.py won't auto-bump past pyOpenSSL's cryptography<46 ceiling +cryptography>=41.0.5,<46 +eventlet==0.41.2 # Note: installs gitpython==3.1.37 (security fixed) under py3.8 and gitpython==3.1.18 (latest available, vulnerable) under py3.6 -gitpython==3.1.45 +gitpython==3.1.61 # Needed by gitpython, old versions used to bundle it gitdb==4.0.12 -# Note: greenlet is used by eventlet -greenlet==3.1.1 -# Gunicorn dropped eventlet support as of v26. https://gunicorn.org/news/#2600-2026-05-05 -gunicorn<26 +gevent==26.8.0 +# Note: greenlet is used by eventlet & gevent (3.2.2 is the minimum common version) +greenlet==3.5.5 +gunicorn==25.3.0 # importlib backport replaces setuptool's pkg_resource. importlib_resources==6.5.2 importlib_metadata==9.0.0 jsonpath-rw==1.4.0 jsonschema==4.26.0 # openapi-spec-validator pinned to align with st2's jsonschema pinning constraint -openapi-spec-validator==0.7.2 -kombu==5.5.4 +openapi-spec-validator==0.9.0 +kombu==5.6.2 lockfile==0.12.2 -mongoengine==0.29.1 -networkx==3.1 +mongoengine==0.29.3 +networkx==3.3 # jsonpath-rw is the only thing that depends on decorator (a transitive dep) -decorator==5.2.1 +decorator==5.3.1 # 202403: Bump oslo.config for py3.10 support. oslo.config==9.6.0 oslo.utils==7.3.0 paramiko==3.5.1 # 202403: bump to 3.0.43 for py3.10 support -prompt-toolkit==3.0.52 +prompt-toolkit==3.0.53 pymongo==4.6.3 -pyparsing==3.1.4 -zstandard==0.23.0 +pyparsing==3.3.2 +zstandard==0.25.0 # pyOpenSSL is a candidate for removal and is not in lockfiles/st2.lock since it is not used. # pyOpenSSL 25.1.0 supports cryptography>=41.0.5,<46 pyOpenSSL<25.2 # 202403: switch from python-editor to editor for py3.10 support -editor==1.6.6 +editor==1.8.0 # editor dependency, required here for inclusion in st2client setup.py -pygments==2.19.2 +pygments==2.21.0 python-keyczar==0.716 -pytz==2025.2 +pytz==2026.3.post1 pywinrm==0.5.0 pyyaml==6.0.3 -redis==6.1.1 -requests==2.32.4 +redis==8.1.0 +requests==2.34.2 # urllib3 is a transitive dep -urllib3==2.2.3 +urllib3==2.7.0 retrying==1.4.2 routes==2.5.1 semver==3.0.4 six==1.17.0 argparse==1.4.0 -argcomplete==3.6.2 -prettytable==3.11.0 +argcomplete==3.7.2 +prettytable==3.18.0 # 20250909 virtualenv 20.34.0 requires typing-extension>=4.13.2 typing-extensions>=4.13.2; python_version < "3.11" # NOTE: sseclient has various issues which sometimes hang the connection for a long time, etc. -sseclient-py==1.8.0 -stevedore==5.3.0 -tenacity==9.0.0 -tooz==6.3.0 +sseclient-py==1.9.0 +stevedore==5.8.0 +tenacity==9.1.4 +tooz==8.1.0 # Note: virtualenv embeds wheels for pip, and setuptools. https://github.com/pypa/virtualenv/src/virtualenv/seed/wheels/embed # virtualenv==21.5.1 embeds pip==26.1.2 setuptools==82.0.1 # lockfiles/st2.lock has pip==25.0.1 wheel==0.45.1 setuptools==75.3.2 -pip==26.1.2 +pip==26.2.1 setuptools==82.0.1 -webob==1.8.9 -webtest==3.0.1 +webob==1.8.11 +webtest==3.0.7 zake==0.2.2 # test requirements below bcrypt==5.0.0 jinja2==3.1.6 mock==5.2.0 pytest==7.0.1 -psutil==7.1.0 +psutil==7.2.2 python-dateutil==2.9.0.post0 python-statsd==2.1.0 -orjson==3.10.15 -zipp==3.20.2 -pynacl==1.6.0 +orjson==3.12.0 +zipp==4.1.0 +pynacl==1.6.2 diff --git a/lockfiles/st2.lock b/lockfiles/st2.lock index 546f12698e..6e58a87720 100644 --- a/lockfiles/st2.lock +++ b/lockfiles/st2.lock @@ -21,6 +21,7 @@ // "editor", // "eventlet>=0.40.3", // "flask", +// "gevent", // "gitdb", // "gitpython", // "graphviz", @@ -133,21 +134,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", - "url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl" + "hash": "f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", + "url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", - "url": "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz" + "hash": "13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", + "url": "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz" } ], "project_name": "annotated-types", - "requires_dists": [ - "typing-extensions>=4.0.0; python_version < \"3.9\"" - ], - "requires_python": ">=3.8", - "version": "0.7.0" + "requires_dists": [], + "requires_python": ">=3.10", + "version": "0.8.0" }, { "artifacts": [ @@ -195,13 +194,13 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "d8f0f22d2a8a7caa383be1e22b6caf1ecaf0ebd10d8f83cc125e36540c95830c", - "url": "https://files.pythonhosted.org/packages/12/f6/5b8ec087cd9cfa9449491ec83f76fb6b7006b4dff57d2ba8aaab330fe8e4/argcomplete-3.7.0-py3-none-any.whl" + "hash": "6029205678bdd9c1c728a155f5f9ecf5812393f969eef58807641a2bc2aa5b19", + "url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "afde224f753f874807b1dc1414e883ab8fe0cda9c04807b6047dcb8e1ac23913", - "url": "https://files.pythonhosted.org/packages/95/c0/c8e94135e66fabf89a120d9b4b123fe6993506beca6c1938a74c24cfa5fd/argcomplete-3.7.0.tar.gz" + "hash": "aad8b69a0b9969edb62db0d1752354c0d50717b10e0cbb00e2a958381b9fc6b9", + "url": "https://files.pythonhosted.org/packages/87/6f/5a73f04007ca950701765949209f068da628bd11f9c2da287278ce91e0ee/argcomplete-3.7.2.tar.gz" } ], "project_name": "argcomplete", @@ -212,8 +211,8 @@ "ruff; extra == \"test\"", "wheel; extra == \"test\"" ], - "requires_python": ">=3.8", - "version": "3.7.0" + "requires_python": ">=3.10", + "version": "3.7.2" }, { "artifacts": [ @@ -491,171 +490,171 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", - "url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl" + "hash": "62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", + "url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", - "url": "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz" + "hash": "741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", + "url": "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz" } ], "project_name": "certifi", "requires_dists": [], "requires_python": ">=3.7", - "version": "2026.6.17" + "version": "2026.7.22" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "379de10ce1ba048b1448599d1b37b24caee16309d1ac98d3982fc997f768700b", - "url": "https://files.pythonhosted.org/packages/79/99/0d0fd37f055224085f42bbb2c022d002e17dde4a97972822327b07d84101/cffi-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl" + "hash": "210019b6c7cf07f081b4c54635c8cf744377001350e29cc0f81c4377b4797735", + "url": "https://files.pythonhosted.org/packages/cb/52/3fa190537004dd7f0ab860a6dc7c0175b8667f68d1e618a46f5498d30250/cffi-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "89095c1968b4ba8285840e131bf2891b09ae137fe2146905acae0354fbce1b5e", - "url": "https://files.pythonhosted.org/packages/04/8c/b925975448cf20634a9fbd5efceb807219db452653648d2897c0989cab2d/cffi-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl" + "hash": "3d22a20b1fb1632cc72c22f95f7b0d2961c3e1c235f245ba4c606c4771035659", + "url": "https://files.pythonhosted.org/packages/09/b8/eefc0e06913b70aa153bf74c946094a18f58fd4aff11b7f372bfdfdca050/cffi-2.1.1-cp310-cp310-musllinux_1_2_i686.whl" }, { "algorithm": "sha256", - "hash": "b6422532152adf4e59b110cb2808cee7a033800952f5c036b4af047ee43199e7", - "url": "https://files.pythonhosted.org/packages/1b/dc/5620cf930688be01f2d673804291de757a934c90b946dbdc3d84130c2ea4/cffi-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" + "hash": "c8c69575568085ba0b1b10c0249d779a214aea6f6522e949a0fc9fb0fcb449d0", + "url": "https://files.pythonhosted.org/packages/10/69/43965eccfdead3b9220015fd1320e117be8c6ed01a62ffab76eeb752f5d5/cffi-2.1.1-cp312-cp312-macosx_10_15_x86_64.whl" }, { "algorithm": "sha256", - "hash": "df2b82571a1b30f58a87bf4e5a9e78d2b1eff6c6ce8fd3aa3757221f93f0863f", - "url": "https://files.pythonhosted.org/packages/1e/85/990925db5df586ec90beb97529c853497e7f85ba0234830447faf41c3057/cffi-2.1.0-cp312-cp312-macosx_10_15_x86_64.whl" + "hash": "42e2f76b9455f5a9a844f770bf3e200ed3da0e15f5df3db9c31fe80b04b3d004", + "url": "https://files.pythonhosted.org/packages/17/0b/ba385d8ccedf926c3cd06e8e2f327027da5afe5f0eb30f1f7bc43ac55125/cffi-2.1.1-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl" }, { "algorithm": "sha256", - "hash": "88023dfe18799507b73f1dbb0d14326a17465de1bc9c9c7655c22845e9ddc3a2", - "url": "https://files.pythonhosted.org/packages/22/d7/1a74539db16d8bfd839ff1515948948efbb162e574650fd3d846896eea95/cffi-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" + "hash": "75f80557d1389eddbd0de2681f6a390a0c5338c31ddaa821381c203fc3fd50d9", + "url": "https://files.pythonhosted.org/packages/18/d4/03026f0c850cbbaa9030750490225b4a7f4d524ea4df72c3cc740a90f4ef/cffi-2.1.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl" }, { "algorithm": "sha256", - "hash": "7762faa47e8ff7eb80bd261d9a7d8eea2d8baa69de5e95b70c1f338bbe712f02", - "url": "https://files.pythonhosted.org/packages/22/f0/a2fc43084c0433caf7f461bccc013e28f848d04ee1c5ed7fce71423cf4d9/cffi-2.1.0-cp311-cp311-musllinux_1_2_i686.whl" + "hash": "7225e4514edb64eb6740324353e0da0711954fd8d7da4576755b1c6e09b697cd", + "url": "https://files.pythonhosted.org/packages/28/f7/dabe6da2466ecbd82dc62e7342dc6b1065dad990c06f00f0ede9ebf2a0ed/cffi-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "4d433a51f1870e43a13b6732f92aaf540ff77c2015097c78556f75a2d6c030e0", - "url": "https://files.pythonhosted.org/packages/38/66/04781a77b411f0bb5b234d62c1814754ab75ebe455ccff1b08e8d7aae98f/cffi-2.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" + "hash": "9f8d177621de5cb38ee3e731eda45d421db093ec0739f46a5594babda7987a98", + "url": "https://files.pythonhosted.org/packages/37/15/180e0dab27b9312c7479003d14c9e547634b7dcb934e2cc4650e1b131a7a/cffi-2.1.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "a016194dbe13d14ee9556e734b772d8d67b947092b268d757fd4290e3ba2dfc2", - "url": "https://files.pythonhosted.org/packages/3b/30/c806937ed5e4c2c7ac30d9d6b76b5dc57ff8b75d83800d9bb11a8253cf2a/cffi-2.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" + "hash": "68e62fe11f30d5ca8289242866f0a5291402d8529ca2178ab8afc5c9694ae890", + "url": "https://files.pythonhosted.org/packages/44/de/f98430906df1545ffde0d543dd124a7a439bc2cd32b36b9c53f805df7333/cffi-2.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" }, { "algorithm": "sha256", - "hash": "c5f5df567f6eb216de69be06ce55c8b714090fae02b18a3b40da8163b8c5fa9c", - "url": "https://files.pythonhosted.org/packages/41/aa/3c1409cdd26094efacd1c36c66e0a6eb9d4296e4fd4f9901b8b2042f4323/cffi-2.1.0-cp310-cp310-musllinux_1_2_i686.whl" + "hash": "f81b3b8f3d4e343550fa4baa0e479bba9f2d29ce9c2e9b51d1ce1718d7442fcf", + "url": "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "19c54ac121cad98450b4896fa9a43ee0180d57bc4bc911a33db6cab1efab6cd3", - "url": "https://files.pythonhosted.org/packages/45/ca/f91641185cdd90c36d317a9dc7f85e88ef8682d8b300977baff5e23c35d8/cffi-2.1.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl" + "hash": "811bd1e21d32de12efca32393a0ab3f5133b54fce9bd44b8bd77ab07da14bf6a", + "url": "https://files.pythonhosted.org/packages/56/e6/8941622732edec876dd17d0453dce07317ae96db34f2ec1436c9d3785986/cffi-2.1.1-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl" }, { "algorithm": "sha256", - "hash": "78474632761faa0fb96f30b1c928c84ebcf68713cbb80d15bab09dfe61640fde", - "url": "https://files.pythonhosted.org/packages/4b/92/e7bb136ad6b5352603732cf907ef862ca103f20f2031c1735a46300c20c9/cffi-2.1.0-cp312-cp312-macosx_11_0_arm64.whl" + "hash": "3143d81e29e1e20a9ce10901ec369012947876596f75a222235965f2b7ae832e", + "url": "https://files.pythonhosted.org/packages/64/b3/f8aa4f3e34986c7e4ec45072d1b1b9dd295b6b18007b45518d79726dd725/cffi-2.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl" }, { "algorithm": "sha256", - "hash": "46b1c8db8f6122420f32d02fffb924c2fe9bc772d228c7c711748fff56aabb2b", - "url": "https://files.pythonhosted.org/packages/4b/a4/77b53abbf7a1e0beb9637edbef2a94d15f9c822f591e85d439ffd91519a6/cffi-2.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl" + "hash": "4a7c934f7360e8cd64fe9efadcbd10c7c6364f531e432b9a4bf5ccbc9e0e8b50", + "url": "https://files.pythonhosted.org/packages/6a/5b/717f1526b9957b34456313c31645c5b82b8fb5c3fe9e4752999be7128bfc/cffi-2.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9", - "url": "https://files.pythonhosted.org/packages/57/5f/ff100cae70ebe9d8df1c01a00e510e45d9adb5c1fdda84791b199141de97/cffi-2.1.0.tar.gz" + "hash": "1dea0e4d7d4f11f619fe8c1d76caf49e24405b4b5743c0e3be16a500ecd930c9", + "url": "https://files.pythonhosted.org/packages/6f/13/4e56852824a03cdf68523a35686f1c28eacd4bd30a7b0a78e682e6e6e1d3/cffi-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "d9fafc5aa2e2a39aaf7f8cc0c1f044a9b07fca12e558dca53a3cc5c654ad67a7", - "url": "https://files.pythonhosted.org/packages/58/0c/f528df19cc94b675087324d4760d9e6d5bfae97d6217aa4fac43de4f5fcc/cffi-2.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl" + "hash": "c8d2c9fd1f2d16f780d15127abb050d13d1a76c03a4bd87d7e4980e45e511e12", + "url": "https://files.pythonhosted.org/packages/70/d2/16d99a0c4948febc0ebd133a13b2f688ff7f8cb04da971e1128872ce0c03/cffi-2.1.1-cp311-cp311-macosx_10_15_x86_64.whl" }, { "algorithm": "sha256", - "hash": "1e9f50d192a3e525b15a75ab5114e442d83d657b7ec29182a991bc9a88fd3a66", - "url": "https://files.pythonhosted.org/packages/62/f2/c9522a81c32132799a1972c39f5c5f8b4c8b9f00488a23feaa6c06f07741/cffi-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" + "hash": "194cffa889098ced9976c3fc6340305e43f6303657d298da55366907c05c22d6", + "url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" }, { "algorithm": "sha256", - "hash": "30b65779d598c370374fefabf138d456fd6f3216bfa7bedfab1ba82025b0cd93", - "url": "https://files.pythonhosted.org/packages/65/68/9f3ef890cf3c6ab97bd531c5677f67613d302165d16f8142b2811782a614/cffi-2.1.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl" + "hash": "ca82be1a1d406ecfe1d25dc16cb33488e5a16bf4438c9fb590484ea29d92478b", + "url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "164bff1657b2a74f0b6d54e11c9b375bc97b931f2ca9c43fcf875838da1570dd", - "url": "https://files.pythonhosted.org/packages/69/aa/24580a278de21fd7322635556334d9b535f1cbc00b0a3919447cdf464c65/cffi-2.1.0-cp310-cp310-macosx_11_0_arm64.whl" + "hash": "dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be", + "url": "https://files.pythonhosted.org/packages/9e/ef/008a1939e372c06329a3fce4279c02f328488f3526744906eeec3da7ad5f/cffi-2.1.1.tar.gz" }, { "algorithm": "sha256", - "hash": "98fff996e983a36d3aa2eca83af40c5821202e7e6f32d13ae94e3d2286f10cfe", - "url": "https://files.pythonhosted.org/packages/6e/28/bd53988b9833e8f8ad539d26f4c07a6b3f6bcb1e9e02e7ca038250b3428d/cffi-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl" + "hash": "208f941bb9d18e768138677f0a6d2ce01f590df56043dda1df1535ac57c88517", + "url": "https://files.pythonhosted.org/packages/a0/d2/6cd24ae3be000a634109c247d1475d62e5616d0dc78c82770942ec384248/cffi-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "c941bb58d5a6e1c3892d86e42927ed6c180302f07e6d395d08c416e594b98b46", - "url": "https://files.pythonhosted.org/packages/88/a9/02cae418ec4beb282ace11958d9d4737793439d561fadc7e6d56f2e2b354/cffi-2.1.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl" + "hash": "5a59cc1c4442bc3d5c703bf720b51138d0bfc173618807c9ee2490a7541dd3d9", + "url": "https://files.pythonhosted.org/packages/a3/b9/0f2e58b2cefa33255bff36935d42b13180fe559bba82596540eb404bde7d/cffi-2.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" }, { "algorithm": "sha256", - "hash": "9d8272c0e483b024e1b9ad029821470ed8ec65631dbd90217469da0e7cd89f1c", - "url": "https://files.pythonhosted.org/packages/a2/a5/d4fe77b589e5e82d43ebc809bf2e6474afe8e48e32ea050b9357645b6471/cffi-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl" + "hash": "a6e721d4b0e45d5b65e87534470e67b18dcd092c83f68fba09f152b9cbc061af", + "url": "https://files.pythonhosted.org/packages/a5/a7/a67c733254d6e7373f7822f8082d8d6beade791e0cf12a7611f376fa61c7/cffi-2.1.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl" }, { "algorithm": "sha256", - "hash": "a5781494d4d400a3f47f8f1da94b324f6e6b440a53387774002890a2a2f4b50f", - "url": "https://files.pythonhosted.org/packages/ba/b0/e131a9c41f10607926278453d9596163594fe1c4ebc46efe3b5e5b34eb84/cffi-2.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl" + "hash": "6e192623c49c94421616a5778fba35cf0d5a8d000650c1967ef4448ee5cdd990", + "url": "https://files.pythonhosted.org/packages/a7/92/500760486c8baab49a7a8a58ba7fc3355ec3974b454b8a09e528efde9e1d/cffi-2.1.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "b65f590ef2a44640f9a05dbb548a429b4ade77913ce683ac8b1480777658a6c0", - "url": "https://files.pythonhosted.org/packages/c0/e9/6d7724983b3d5a0908dbf74f64038ade77c18646ff6636ec7894fd392ce1/cffi-2.1.0-cp310-cp310-macosx_10_15_x86_64.whl" + "hash": "154852545011f779917b11c78db2358d095da62a9a172b78ad0a583ee5adc0d0", + "url": "https://files.pythonhosted.org/packages/ad/5a/4707a0dc1f203f5dde5a907b0d4e3c25d71120241048bd5bc6f1bb9d4e71/cffi-2.1.1-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl" }, { "algorithm": "sha256", - "hash": "5972433ad71a9e46516584ef60a0fda12d9dc459938d1539c3ddecf9bdc1368d", - "url": "https://files.pythonhosted.org/packages/c3/c0/d1ec30ffb370f748f2fb54425972bfef9871e0132e82fb589c46b6676049/cffi-2.1.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl" + "hash": "3311ed60d36f83378794e1009ac6258bafbf81f7888b4caa7b35a521e3f95813", + "url": "https://files.pythonhosted.org/packages/ad/66/c19feabb28485b6e0bbaaafa90837a1ef5d302e90f2178bd33f17a49879b/cffi-2.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" }, { "algorithm": "sha256", - "hash": "3d7f118b5adbfdfead90c25822690b02bc8074fba949bb7858bec4ebd55adb43", - "url": "https://files.pythonhosted.org/packages/d0/9a/bb1d5ed9c3fcae158e9f6391bf309c95d98c2ac37ed56573228471d0af5e/cffi-2.1.0-cp310-cp310-musllinux_1_2_aarch64.whl" + "hash": "5bb4e7ea95dcd6a014a6fef62e62467d67d8e582326443f3d68e71d6320a9fcf", + "url": "https://files.pythonhosted.org/packages/b0/ae/679bf47e73fd77b352171727f07de559a003f14de5d02b904a6ec1fa73ca/cffi-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "02cb7ff33ded4f1532476731f89ede53e2e488a8e6205515a82144246ffa7dcc", - "url": "https://files.pythonhosted.org/packages/d3/67/85c89a59ba36a671e79638f44d466749f08179266a57e4f2ffdf92174072/cffi-2.1.0-cp311-cp311-macosx_10_15_x86_64.whl" + "hash": "c1453022f490d2459a11819d83ad1d586e9ff65a12ac3e705ffebd46d3685dcf", + "url": "https://files.pythonhosted.org/packages/b1/db/dceb9dd5b231e1da801793f8acc9f3c52a7e1afe40bb1aae37e02b0faad5/cffi-2.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" }, { "algorithm": "sha256", - "hash": "f5bce581e6b8c235e566a14768a943b172ada3ed73537bb0c0be1edee312d4e7", - "url": "https://files.pythonhosted.org/packages/ea/dd/e3b0baa2d3d6a857ac72b7efbf18e32e487c9cdafcc13049ad765495b15e/cffi-2.1.0-cp311-cp311-macosx_11_0_arm64.whl" + "hash": "f5cfbc5fe74540d335175b656c725d74d90e3730c626d92575eea35029d9afaa", + "url": "https://files.pythonhosted.org/packages/b4/c6/ab025d75d2c26c19b087c0124e75ee31cb65032f4fe345d356d8c507ab97/cffi-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "0a96b74cda968eebbad56d973efe5098974f0a9fb323865bf99ea1fd24e3e64c", - "url": "https://files.pythonhosted.org/packages/ec/d1/9a5b7169499e8e8d8e636de70b97ac7c9447104d2ff1a2cd94790cea5162/cffi-2.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl" + "hash": "baed1e86cc735622097354b9d1281406caf42ff42a886d29faa8e8d1630333be", + "url": "https://files.pythonhosted.org/packages/b6/d2/2cde336b375f55c76ca670f0be3978cc048e31e24f3b4d7ce8473150a388/cffi-2.1.1-cp310-cp310-macosx_10_15_x86_64.whl" }, { "algorithm": "sha256", - "hash": "03e9810d18c646077e501f661b682fbf5dee4676048527ca3cffe66faa9960dd", - "url": "https://files.pythonhosted.org/packages/f9/cf/398272b8bbfd58aa314fda5a7f1cdbb26d1d78ae324a11211521315dd1f0/cffi-2.1.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl" + "hash": "398aff33cee2767e3e781d2554c54bd0dff386bb437581e0d8011fde1a942ec1", + "url": "https://files.pythonhosted.org/packages/cd/95/31b535a9f0220ae9f357de4a08d57ce89cb417653c2fd9f075f50822a388/cffi-2.1.1-cp311-cp311-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "11b3fb55f4f8ad92274ed26705f65d8f91457de71f5380061eb6d125a768fecd", - "url": "https://files.pythonhosted.org/packages/fa/75/74dfb7c3fc6ebbd408038476bd4c1d7e925c62614e7b9c534ecc34218288/cffi-2.1.0-cp310-cp310-musllinux_1_2_x86_64.whl" + "hash": "df913725b79db7bcf03448f36b7bf8815363417d5b58deecf9305e3e30f0f21a", + "url": "https://files.pythonhosted.org/packages/ce/87/616202d8e51342c07d2534c510111c4cc37201775ce8f60802c9335d1edd/cffi-2.1.1-cp311-cp311-musllinux_1_2_i686.whl" }, { "algorithm": "sha256", - "hash": "aa7a1b53a2a4452ada2d1b5dade9960b2522f1e61293a811a077439e39029565", - "url": "https://files.pythonhosted.org/packages/fb/d2/4398416cd699b35167947c6e22aca52c47e69ad5695073c9f1f2c52e04aa/cffi-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" + "hash": "34e261f78cb6ceaaa36f42f2613f4380d94d9c759a9c73c769ee6e0247364632", + "url": "https://files.pythonhosted.org/packages/f7/a4/4399daaf8f7dfee9d7c3327fdb0426ee041cc63edc358b93911ceb2bfc7a/cffi-2.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" } ], "project_name": "cffi", @@ -663,268 +662,378 @@ "pycparser; implementation_name != \"PyPy\"" ], "requires_python": ">=3.10", - "version": "2.1.0" + "version": "2.1.1" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "1173b74051570cf08099d7429d92e4882d375ad4217f92a6e5240ccfb26f231e", - "url": "https://files.pythonhosted.org/packages/8c/6c/0a40afdb50a0fe041ab95553b835a8160b6cf0e81edf2ae2fe9f5224cbf9/chardet-7.4.3-py3-none-any.whl" + "hash": "4076d795897ce45239825956a1334e134322ecc4bfe84dbb12acd5390de0fbc1", + "url": "https://files.pythonhosted.org/packages/cf/6e/5a0b348fa4cd7847567a28c6e697ccf58391960bfd13a6e7473ee23ca2f2/chardet-7.6.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "7005c88da26fd95d8abb8acbe6281d833e9a9181b03cf49b4546c4555389bd97", - "url": "https://files.pythonhosted.org/packages/14/4b/d3c79495dee4831b8bebca2790e72cb90f0c5849c940570a7c7e5b70b952/chardet-7.4.3-cp311-cp311-macosx_11_0_arm64.whl" + "hash": "aa03322e07ac08d520ec50bb50c73143d0892d1adc067d4c5e58f4ef4b2363a8", + "url": "https://files.pythonhosted.org/packages/03/25/9c8db4f951e974a4db5558d9eea62e1fd5b5889c9d0ad0315eed67c5cdb3/chardet-7.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "3990fffcc6a6045f2234ab72752ad037e3b2d48c72037f244d42738db397eb75", - "url": "https://files.pythonhosted.org/packages/18/ef/ea4edec8c87f7e6eda02673acc68fe48725e564fc5a1865782efb53d5598/chardet-7.4.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "6424512f576fa7e88b7431d38a42d57552c8f717465a975fc42e497cd280d833", + "url": "https://files.pythonhosted.org/packages/11/2e/d8634bee23a07bf512512ddf6218a68e47f045ae061c0cc80657ed79dcc0/chardet-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl" }, { "algorithm": "sha256", - "hash": "25a862cddc6a9ac07023e808aedd297115345fbaabc2690479481ddc0f980e09", - "url": "https://files.pythonhosted.org/packages/19/52/505c207f334d51e937cbaa27ff95776e16e2d120e13cbe491cd7b3a70b50/chardet-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl" + "hash": "7b586cab9e9072dddd89bc2bd27ee72808d0c84ec73695fe6ec0f3c46b057c65", + "url": "https://files.pythonhosted.org/packages/20/38/b32daa70f8bacd47e515ec9f85d571c87f31ff1c43c95aea7780eaefe7fc/chardet-7.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "cc1d4eb92a4ec1c2df3b490836ffa46922e599d34ce0bb75cf41fd2bf6303d56", - "url": "https://files.pythonhosted.org/packages/19/b6/9df434a8eeba2e6628c465a1dfa31034228ef79b26f76f46278f4ef7e49d/chardet-7.4.3.tar.gz" + "hash": "a12023d48d0e207791c01161d03cb3c0d85c6a15f345eb9d3d56063a63d1e40f", + "url": "https://files.pythonhosted.org/packages/44/99/934fb862d102c8756008597f4398323f32cef329f16e87fbb3bf76d4f4be/chardet-7.6.0-cp312-cp312-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "626f00299ad62dfe937058a09572beed442ccc7b58f87aa667949b20fd3db235", - "url": "https://files.pythonhosted.org/packages/36/21/edb36ad5dfa48d7f8eed97ab43931ecdaa8c15166c21b1d614967e49d681/chardet-7.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "284136186ff90735f901ed0a1c6d41e7af67c666841cc0eceb58482a21b7056c", + "url": "https://files.pythonhosted.org/packages/55/95/bd6d59026638cec47dace85858171fbecadd2f9e58cb2b973dc515aa790c/chardet-7.6.0-cp311-cp311-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "75d3c65cc16bddf40b8da1fd25ba84fca5f8070f2b14e86083653c1c85aee971", - "url": "https://files.pythonhosted.org/packages/61/33/29de185079e6675c3f375546e30a559b7ddc75ce972f18d6e566cd9ea4eb/chardet-7.4.3-cp312-cp312-macosx_10_13_x86_64.whl" + "hash": "cf6d08c2373b7772a558d141f9e8cee53fe1d222341bac612e4d558b04995f73", + "url": "https://files.pythonhosted.org/packages/56/1d/49f13052b74303bab2789d098063cbd19758217949ea54ffa216b6098cb3/chardet-7.6.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "c0c79b13c9908ac7dfe0a74116ebc9a0f28b2319d23c32f3dfcdfbe1279c7eaf", - "url": "https://files.pythonhosted.org/packages/6b/1b/7f73766c119a1344eb69e31890ede7c5825ce03d69a9d29292d1bd1cfa1b/chardet-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl" + "hash": "19fea52164e6e00f2a21ed418f42e4b0162a09199274c86d07ad3efd661317c4", + "url": "https://files.pythonhosted.org/packages/6f/62/64da80dad0c804e743b4156f379183578f1e33918856ae928dc9248a6002/chardet-7.6.0-cp312-cp312-macosx_10_13_x86_64.whl" }, { "algorithm": "sha256", - "hash": "93c45e116dd51b66226a53ade3f9f635e870de5399b90e00ce45dcc311093bf4", - "url": "https://files.pythonhosted.org/packages/6c/63/0f43e3acf2c436fdb32a0f904aeb03a2904d2126eed34a042a194d235926/chardet-7.4.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "249993b88ac7a58cad2781acea8f379152a28a719c9b401d614898c63a8c83da", + "url": "https://files.pythonhosted.org/packages/71/e9/b04e0ec576a77e79fe37279a9a5d5b1ae752d365e43df2eca0d0eee4cea5/chardet-7.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "cfb54563fe5f130da17c44c6a4e2e8052ba628e5ab4eab7ef8190f736f0f8f72", - "url": "https://files.pythonhosted.org/packages/87/23/e31c8ad33aa448f0845fd58af5fc22da1626407616d09df4973b2b34f477/chardet-7.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + "hash": "0ad9bc6dab4f338673353fa3f0dc96122f559aaf746087408106e2fcbf132fe8", + "url": "https://files.pythonhosted.org/packages/76/1b/59eb88a78d8f5855c27c25788088df82834ad067f3dddaf4d86ef03cf2d3/chardet-7.6.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "5d2879598bc220689e8ce509fe9c3f37ad2fca53a36be9c9bd91abdd91dd364f", - "url": "https://files.pythonhosted.org/packages/87/2e/e1ee6a77abf3782c00e05b89c4d4328c8353bf9500661c4348df1dd68614/chardet-7.4.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "2cf0adaca8b1c4bacfade9d0a1e4f8f70b1bb122833d6f07ab90e3adc84eb13a", + "url": "https://files.pythonhosted.org/packages/7d/a2/c4d99299e9ce7fad561f8bb56babbbbdd3bb6b4fbd7c0ec674c1dbdd2cc5/chardet-7.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "bba8bea1b28d927b3e99e47deafe53658d34497c0a891d95ff1ba8ff6663f01c", - "url": "https://files.pythonhosted.org/packages/8b/02/b677c8203d34dad6c2af48287bb1f8c5dff63db2094636fbe634b555b7fb/chardet-7.4.3-cp310-cp310-macosx_11_0_arm64.whl" + "hash": "5e9b31b9ae93872d66439b046a1e08c2ea99791f3c254dce1e2633e395c5587c", + "url": "https://files.pythonhosted.org/packages/7f/4a/60ed03656b28c1f4d378bc3cfe8a6cdda62c7c289398f925610fbbabfd00/chardet-7.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "29af5999f654e8729d251f1724a62b538b1262d9292cccaefddf8a02aae1ef6a", - "url": "https://files.pythonhosted.org/packages/9c/2f/4c5af01fd1a7506a1d5375403d68925eac70289229492db5aa68b58103d8/chardet-7.4.3-cp312-cp312-macosx_11_0_arm64.whl" + "hash": "cbaca8f563a9de07ab1a53157dba93802e54c26afe3339892afcc7c59ea4ef1b", + "url": "https://files.pythonhosted.org/packages/8c/cd/dc9df6b57c043037920a3896ccb08a21e0595fe592b7acb9fc85acaf0698/chardet-7.6.0-cp310-cp310-macosx_10_9_x86_64.whl" }, { "algorithm": "sha256", - "hash": "4c3da294de1a681097848ab58bd3f2771a674f8039d2d87a5538b28856b815e9", - "url": "https://files.pythonhosted.org/packages/b1/10/31932775c94a86814f76b41c4a772b52abfb0e6125324f32c6da1196c297/chardet-7.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + "hash": "dde4080fb6bb8db96e8c44893771bcc0d235f4c22cdddb194a765a65e3a72ba7", + "url": "https://files.pythonhosted.org/packages/ad/be/1c57863e21c1d6cb6b0fcdde313f8a24039eca01cc90ef0f0986c0964969/chardet-7.6.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "dc50f28bad067393cce0af9091052c3b8df7a23115afd8ba7b2e0947f0cef1f8", - "url": "https://files.pythonhosted.org/packages/b9/99/f6a822ad1bde25a4c38dc3e770485e78e0893dfd871cd6e18ed3ea3a795e/chardet-7.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "93d9df6089ded42ed1fe9f57e272c0b74bd0464d45c0c7d50f09f26f31105c3c", + "url": "https://files.pythonhosted.org/packages/b1/51/cd61c567092a6cec796144510a68aff158ebfc1df82950a45bae65f28413/chardet-7.6.0.tar.gz" }, { "algorithm": "sha256", - "hash": "23163921dccf3103ce59540b0443c106d2c0a0ff2e0503e05196f5e6fdea453f", - "url": "https://files.pythonhosted.org/packages/c4/4b/1361a485a999d97cac4c895e615326f69a639532a52ef365a468bd09bad1/chardet-7.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "55a4c31adc7c7e83ad412f2f66b6b7358d0d4fe67505e7f58e18f68f75d341bb", + "url": "https://files.pythonhosted.org/packages/b9/66/acab13c5bbe55410273530a41b83fdcde0b653f6bded34702504c0ab95cb/chardet-7.6.0-cp310-cp310-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "9a4904dd5f071b7a7d7f50b4a67a86db3c902d243bf31708f1d5cde2f68239cb", - "url": "https://files.pythonhosted.org/packages/e5/59/a32a241d861cf180853a11c8e5a67641cb1b2af13c3a5ccce83ec07e2c9f/chardet-7.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + "hash": "4b81d3f7d7914442d5f7d515b8c6d79cee6b794bc208971fb6902f176671166a", + "url": "https://files.pythonhosted.org/packages/f2/34/0fd9d566df9647d0820a35b4d119db971da3ae9be20899d2b4af11d7ab58/chardet-7.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" } ], "project_name": "chardet", "requires_dists": [], "requires_python": ">=3.10", - "version": "7.4.3" + "version": "7.6.0" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5", - "url": "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl" + "hash": "6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6", + "url": "https://files.pythonhosted.org/packages/cc/61/d01fc49b8dea277640b55a9e15960dbca9fdc8c9fde18e572d39c59f4019/charset_normalizer-3.5.1-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "e9fbdce1e47394b09bc9f26ab117dfc8d6491977a11d86f592bb42c779db2fda", + "url": "https://files.pythonhosted.org/packages/03/6d/439231dfc3ccfa6f8c06477b7da2219cbd41a2de3d49084df8ec7b5100f2/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "c7b742bf31c88566b4bb6335a7f393bb322e580b6bb98df7bd0c25e6e3519ce8", + "url": "https://files.pythonhosted.org/packages/0d/35/731ac04aa0a097fc1c97f0994c375bdb230c6c96619db794208fe664e9ce/charset_normalizer-3.5.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "4c4fb141a727957c93edfe5c32a26ceb6b5f6461d67146e2d39f51e16170bea8", + "url": "https://files.pythonhosted.org/packages/18/96/2b3a21492d9f65171ac75d872f5018260013d00bfa0ff70ec9f179148cbd/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_ppc64le.whl" + }, + { + "algorithm": "sha256", + "hash": "07ffd07412fc5d5e84cd8952acf9ff7e4ed7a708e69d1bada19d8ba91711353f", + "url": "https://files.pythonhosted.org/packages/20/c8/c36f6e0b2dfec351bd38cbc05362697e58bcd073d7dbd95154290c9714ce/charset_normalizer-3.5.1-cp310-cp310-musllinux_1_2_ppc64le.whl" + }, + { + "algorithm": "sha256", + "hash": "0722590aabf9dc6a6c0343d523c05458fa2b5047dbe6302fd526bb570600753f", + "url": "https://files.pythonhosted.org/packages/28/f0/0c0ceec6d98b7daa62e361e418135d59685811d79ba11529aad5cdf15e84/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "36047af20e17097c3bb9476c2b7655f2f7aa51322c0ba58c07695bedf755a950", + "url": "https://files.pythonhosted.org/packages/2b/b8/11d4840bfc99330cc7fbcc2681ee5a044553a6e77655508d8f9b2bff7b34/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_armv7l.whl" + }, + { + "algorithm": "sha256", + "hash": "5b6d1386bf0096d26d3a863dc0a487a5b4eb9aa93cf5ba69683d29dde6b9d60f", + "url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl" + }, + { + "algorithm": "sha256", + "hash": "96eefc178f8636b9c760c5829345307fd81cfae9ab1e80997dbddeb0f54ee9a3", + "url": "https://files.pythonhosted.org/packages/32/cd/4f564b8f132de25db594efc706897069f016790cea63a5669c9df2675f64/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "7235dc28fc6dd9d832ac7c7bce95367dedb85929f17368a0c2bee1e080b9acbf", + "url": "https://files.pythonhosted.org/packages/35/5a/337e4663a5eae6de99db940ee8066d4145caafb61327db62deda15313cce/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_riscv64.whl" }, { "algorithm": "sha256", - "hash": "5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd", - "url": "https://files.pythonhosted.org/packages/01/c4/4fa4c8b3097a11f3c5f09a35b72ed6855fb1d332469504962ab7bafcc702/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + "hash": "3588e376b3ea2eea84976f67273d679f229e24c66dce7b82ae45aef04ff6e072", + "url": "https://files.pythonhosted.org/packages/35/8a/3d130aeabcaf3d2466af76b7b141c08d9e89c9016ab4b7cdd0f7dc2d1c62/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_s390x.whl" }, { "algorithm": "sha256", - "hash": "0e94703ec9684807f20cfb5eed95c70f67f2a8f21ad620146d7b5a13677b93e5", - "url": "https://files.pythonhosted.org/packages/0b/e3/85ec501f206fb049259288c1f3506e53876937fb00edb47009348e66756b/charset_normalizer-3.4.9-cp311-cp311-macosx_10_9_universal2.whl" + "hash": "7c0c10730342b0c9b35dd1d619beb8214e520bd96a1f870f452680b238aab3e0", + "url": "https://files.pythonhosted.org/packages/38/fe/341861ac118dae06f3ec0eb487488af52128f2ef2faf0b11003944d22259/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" }, { "algorithm": "sha256", - "hash": "871ff67ea1aad4dfd91736464934d56b32dac49f9fbe16cddba36198a7b3a0db", - "url": "https://files.pythonhosted.org/packages/0c/74/2f62c8821b969ea3bd67cc2e6976834f48ca5d12664d2559ebcd9bcfbed7/charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "bd6c173f04743d483881bffa1478d5a4624475b8cd1d2194956a75548e191c18", + "url": "https://files.pythonhosted.org/packages/42/85/f9e22af69af67c54cce42be9455d9c81294f918b4ccc454db01f66efcac2/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "65a7ff3f705e57d392f7261b6d0550fe137c3019477431f1c355e0db0a7d3e15", - "url": "https://files.pythonhosted.org/packages/0c/e7/aaf6da33fc9f4691cda8f7efbc9f69179d3d39ec8a4799baf273ee1d8db0/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_armv7l.whl" + "hash": "5d8531a6569d025f68e2321e7638fb7978f23db58e5f69f56913837aae03816e", + "url": "https://files.pythonhosted.org/packages/46/22/111e5be3b740d5c2a5bfcedb3d237b6591e5c2e82ae9d6ffcb121fe0909c/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_armv7l.whl" }, { "algorithm": "sha256", - "hash": "e9701d0049d92c16703a42771b98d560b95248949f23f8cf7b4eddd201814fb9", - "url": "https://files.pythonhosted.org/packages/1d/85/181c652953eb5276d198f375b1dd641047392050098100a3a02d6534f657/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_aarch64.whl" + "hash": "343fb4f2821043bd87095f7b08a1a181febc8e36ac64212143bbfd0a0e1bc235", + "url": "https://files.pythonhosted.org/packages/49/e0/716601f3cc69be7b198951150c75ead1ece33c3c8036ff6ffa46029659a0/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl" }, { "algorithm": "sha256", - "hash": "60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde", - "url": "https://files.pythonhosted.org/packages/33/9a/895095b83e7907abd6d3d99aad3a38ad0d9686cc186cb0c94c24320fe63e/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_aarch64.whl" + "hash": "00668ebb0609751758682eb0b5857e7c35b9f00e84dfdef062e103244ec94d45", + "url": "https://files.pythonhosted.org/packages/55/53/7d819bd23a00ef45039146fa2cce1daa2f0771e758c5653ee1f6edac91ed/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl" }, { "algorithm": "sha256", - "hash": "bcf74c1df76758a395bf0af608c04c82257523f55c9868b334f06270d0f2112b", - "url": "https://files.pythonhosted.org/packages/36/31/a276bb2e66243072a3fd06fdcab9cbb61a305b02143d70d2bda21d888fa8/charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_armv7l.whl" + "hash": "494b70049a4d69aec6e8137c13af4cf8db8c9f9820a1392ac293b0dd2987a818", + "url": "https://files.pythonhosted.org/packages/58/ad/b9aecf38d805cbcf84fa94f14c5d972a16561e20296a11dc799a5dcf3763/charset_normalizer-3.5.1-cp310-cp310-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "c0323c9daef75ef2e5083624b4585018a0c9d5e3b40f607eed81a311270b934b", - "url": "https://files.pythonhosted.org/packages/44/95/80282cce0fae9c3061203d723ee87da996aed79679e65d8935050ee7ca1f/charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_armv7l.whl" + "hash": "41876ee62a3dddf48ff1121ad8f0798032aa03f2fd35f21f34a4cab14f18d8d2", + "url": "https://files.pythonhosted.org/packages/5b/97/fb4e82231aba271ffd775a1b4993b0defc4e3059f286ae41d9433409fe85/charset_normalizer-3.5.1-cp37-abi3-macosx_10_9_universal2.whl" }, { "algorithm": "sha256", - "hash": "9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44", - "url": "https://files.pythonhosted.org/packages/4b/4c/5361f9aa7f2cb58d94f2ab831b3d493f69efb1d239654b4744e3c09527cb/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" + "hash": "ce854f5f478050ade5a238731c4ca985a7d3b3cb53ff600a9b5c3b689b5f0a7a", + "url": "https://files.pythonhosted.org/packages/69/2b/d8be3523ddf9f0b0f3e56d1359034aa10653a4d11564c697f802b4775766/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" }, { "algorithm": "sha256", - "hash": "4773092f8019072343a7447203308b176e10199920eb02d6195e81bbb3274c29", - "url": "https://files.pythonhosted.org/packages/4e/6e/de0229a7ef40f6f9d28a837eebf4ec47bdca5dab4e900c84f22919af636a/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" + "hash": "eda059b6bc8bc0812d626fd91a7ce01bf583df0a61296eff390fd94141a34e30", + "url": "https://files.pythonhosted.org/packages/6a/b6/034f6802e9c3f6418966cfabb7db8c9252cc2429c5098f41cc43af804149/charset_normalizer-3.5.1-cp311-cp311-macosx_10_9_universal2.whl" }, { "algorithm": "sha256", - "hash": "7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9", - "url": "https://files.pythonhosted.org/packages/50/78/ce342ca4ff30b2eb49fe6d9578df85974f90c67d294113e94efdd9664cbd/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" + "hash": "b9af956078716df40d985fb0dfeb2c2120c5ca92ba4ff4b388acfd01cdc14d08", + "url": "https://files.pythonhosted.org/packages/6f/89/bb5108dc6c3651dca963f2b0a3ba19bbcb370c94e1b6d3e0e844a58e6dca/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "b5314963fce9b0b12743891de876e724997864ee22aa496f903f426c7e2fa5b2", - "url": "https://files.pythonhosted.org/packages/5e/be/7ee4453d7e88dfbc4104ccd34900b9f2c7c17dac22881865fe0e82424a25/charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "d1ee1e296209fdce05b81b663250eefa02213a2da7b41bf26f7829b8ba3545aa", + "url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl" }, { "algorithm": "sha256", - "hash": "79580094b00d1789d1f93ea55bc43cb2f611910c72235b7657f3482ddcc1b22d", - "url": "https://files.pythonhosted.org/packages/63/01/f2fb3bd3a73be48b173ee0c6aa8d2497af97d5663a8c4c4b491de4c62f7a/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_x86_64.whl" + "hash": "a2028475ba855475b8b4d3cfeb4994269c967aea8b9892dfba907f4263a863a3", + "url": "https://files.pythonhosted.org/packages/75/9c/019fbb9f4834491a160951349b1a3714439376f66e5f7cf18b4f18f0c7aa/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0", - "url": "https://files.pythonhosted.org/packages/70/4a/ecbd131485c07fcdfad54e28946d513e3da22ef3b4bd854dcafae54ec739/charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl" + "hash": "1d1c7a53a6c2103925cdd6d7229f8c567379f211c869793df679f2e9f738c369", + "url": "https://files.pythonhosted.org/packages/76/84/6f1290fa07ae6978d3960caa3eb1b8019bf9284ab7c2297b00c099ef4250/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl" }, { "algorithm": "sha256", - "hash": "16d10d789dd9bcca1173c95af82c58433122564b7bc39385124be735a35cbe99", - "url": "https://files.pythonhosted.org/packages/7f/f4/ffbb83546e1f198ecc70ecd372b65cf2b50f9068b380abd67640f17a8e18/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" + "hash": "e199fb99720074809a7720f1c0b4d919eea8b87e88713e0f8f602f7bef543d9d", + "url": "https://files.pythonhosted.org/packages/80/c2/a7379b840292d0c1ab9fbd17d1f3967aa81794dc95bc74be8999d7fedcf7/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "c1225416b463483160e4af85d5fc3a9690ccb53fd4b1865a6437825f5ede3209", - "url": "https://files.pythonhosted.org/packages/80/33/6c99c1b3e6b8bf730e1bc809b9a2608f224145069114c479a2e9e1494346/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" + "hash": "b54e7e13267d49ffbfe68e25b3cbd774dab38fa37238f71265e91b36146eb21c", + "url": "https://files.pythonhosted.org/packages/82/38/083a24028304bc85bb9e376fed801178423dcbb67495f73b6ea0624e1894/charset_normalizer-3.5.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" }, { "algorithm": "sha256", - "hash": "03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62", - "url": "https://files.pythonhosted.org/packages/83/dc/9b29fa4412b318bf3bfea985c35d67eb55e04b59a7c3f2237168b0e0be6f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_x86_64.whl" + "hash": "950f23cb393f85543777b0433f082cddd25b51ab398eac7971146495679efe5f", + "url": "https://files.pythonhosted.org/packages/87/bd/fbc24d825c66f1c74f6ccdea3742c3d8354a4888e86d1315a197fee69061/charset_normalizer-3.5.1-cp310-cp310-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84", - "url": "https://files.pythonhosted.org/packages/87/3a/ad914516df7e358a81aae018caa5e0470ba827fa6d763b1d2e87d920a5f6/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_armv7l.whl" + "hash": "4582c27e8c889d64811987b5967fbd3ae0c823fe1fd933b543d55ac20bb475fa", + "url": "https://files.pythonhosted.org/packages/9a/4c/be49ada26b1f0232d57aa89bbebf997a5cc2332a5616b6eca26ff680044d/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39", - "url": "https://files.pythonhosted.org/packages/a1/34/ef5c05f412f42520d7709b7d3784d19640839eb7366ded1755511585429f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_armv7l.whl" + "hash": "a6dac12ff6b846103483683f60c5f8fee205121adc58ffd87e90a90a3af69e99", + "url": "https://files.pythonhosted.org/packages/9f/2f/fe3f187327aac18e2d54e9d2b08e15d27bf9b642d9e51c219f130fc34d1a/charset_normalizer-3.5.1-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" }, { "algorithm": "sha256", - "hash": "04ce310cb89c15df659582aee80a0603788732a5e017d5bd5c81158106ce249c", - "url": "https://files.pythonhosted.org/packages/a5/34/49b9060e8418b14fb5cba9cf6bfb383111e2538a03a1fb18e66a95aeb3d5/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + "hash": "0b2b1b3fa5670c127b246df1d0c059defd41f689a868a3b9d79df9b1cac42d22", + "url": "https://files.pythonhosted.org/packages/a4/c8/ab42b07cfd82e919f427fcfaa7c41abae8242833ad1aad66d42bae40b669/charset_normalizer-3.5.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl" }, { "algorithm": "sha256", - "hash": "3d92613ec25e43b05f042302531ec0f00b8445190e43325880cbd6ab7c2581da", - "url": "https://files.pythonhosted.org/packages/a5/ff/c946d63bc3786d5b84d960b0f7ab7e25b828486a946b5aa997625bcaf6a6/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_armv7l.whl" + "hash": "f9f8405c2c758532c74fed975dbee57be1f31a6e865c031870c79a6ed3212ada", + "url": "https://files.pythonhosted.org/packages/b1/ba/ef83ae3aca816393decfa3530976f38a79812d707b80b580ac33b83f9877/charset_normalizer-3.5.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "cd6280cf040f233bd7d3407b743b4b4c74f70e8e1c4199cb112a62c941c0772a", - "url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl" + "hash": "ba2f37ee79e6338845261a3c5b1784e5d1acdff2c0785b284f1b633033d136ab", + "url": "https://files.pythonhosted.org/packages/b2/2c/45847198c16f4b38090cc7423b2b6a9008e438704d8ab413211832498d31/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "280081916dc341820640489a66e4696049401ef1cf6dd672f672e70ad915aca3", - "url": "https://files.pythonhosted.org/packages/af/ba/5e5007c370702f85d2ef75791fac7943ed41e080364a673b20142e430e3e/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_x86_64.whl" + "hash": "ba501e667c17d8411f98e67a022d9604ef179aff0e459b7e292c796837c13573", + "url": "https://files.pythonhosted.org/packages/b7/52/643d11ffd60e9ac2fd1fb87e167a19285b9eefeff4a40e63c87cbfbeab36/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "304b13570067b2547562e308af560b3963857b1fa90bd6afd978130130fe2d6a", - "url": "https://files.pythonhosted.org/packages/b3/46/03ddc7da576d814fe0a36dd1f0fd3258e95404b4b2e3c026b7923d7e133f/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" + "hash": "c1dcc36dcb96abc02236e182d17e0f71430152a6c2c7447421da2d2dc144edea", + "url": "https://files.pythonhosted.org/packages/b9/2d/918d0e98a0e679469ed05bb2d90c2088b4d315bb612969d8499f76fb5210/charset_normalizer-3.5.1-cp310-cp310-musllinux_1_2_armv7l.whl" }, { "algorithm": "sha256", - "hash": "673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b", - "url": "https://files.pythonhosted.org/packages/bd/2a/23f34ec9d04624958e137efdc394888716353190e75f25dd22c7a2c7a8aa/charset_normalizer-3.4.9.tar.gz" + "hash": "a545775cfe815855ea32d7c27731d79da358ef2055b4a25830231b1622dd18aa", + "url": "https://files.pythonhosted.org/packages/b9/90/082cc45599c392f28c036a497f49e0634041a785fc3849c80ccf396d096f/charset_normalizer-3.5.1-cp310-cp310-musllinux_1_2_s390x.whl" }, { "algorithm": "sha256", - "hash": "2a441ea71902098ffe78c5abe6c494f44160b4af614ed16c3d9a3b1d17fd8ee2", - "url": "https://files.pythonhosted.org/packages/c3/69/2a5385192e67175f7d8bd5ce4f57c24bc956439adeae5c13a99aa28a53d1/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "6e2912d4babbc65196ac13c2f53468dc57fb8b9c25ef913e8c59ddf7c6dc0e1b", + "url": "https://files.pythonhosted.org/packages/ba/ed/1dd7cfebb4e75812934c49ca3b79757d11948053f7937ab7070c151f3c55/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_s390x.whl" }, { "algorithm": "sha256", - "hash": "9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b", - "url": "https://files.pythonhosted.org/packages/d7/74/3c12f9755717dfe5c5c87da63f35d765fa0c00382ec26bf23f7fae34f2ba/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "3d27167433c0d5f18dc850f07d0b3816221984fecdc405d6c157a6f0b8f8e9e6", + "url": "https://files.pythonhosted.org/packages/bf/eb/239c84503cc9e3ba6eb34686a24bc66e84f3924efdd7e38e751a19f6bc10/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "67830fc78e67501f47bb950471b2dcb9b35b140084429318e862895a8e89c993", - "url": "https://files.pythonhosted.org/packages/d9/8d/feabb82cb49fcad14515b1d7d1ca4787b0da7fc723a212bf89bc9e0fac52/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_aarch64.whl" + "hash": "4b599739b93b2cbeded49645ae3c8d1405c29ddfbceac1545c87a3f9580a9e96", + "url": "https://files.pythonhosted.org/packages/c3/92/de7e32ed05341e7a9c4c877c318418197b7f2d66a3b68d561bf2ac57ca3e/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" }, { "algorithm": "sha256", - "hash": "aa99adc8f081b475a12843953db36831eaf83ec33eb46a90629ca6a5de45a616", - "url": "https://files.pythonhosted.org/packages/de/d1/b4319dc3229d8272fba305e206fc0a148e2de8d4087917ce62ae6382f359/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "f5542f9b941279d82d41eb0aa9f98eba36fe4df5c7086c651df7944935b37182", + "url": "https://files.pythonhosted.org/packages/ca/7b/311b3e02e8c4092400c449c850a760d8c45d900983c83a70cc07208c551d/charset_normalizer-3.5.1-cp310-cp310-musllinux_1_2_riscv64.whl" }, { "algorithm": "sha256", - "hash": "9bb41182d93ea91f60b4bc8fbf4c820c69ef8a12ab2d917f3f1834f1acad07e8", - "url": "https://files.pythonhosted.org/packages/e8/5f/b98b8da398637b551e427e7be922bdec19177dc54d6811dcdaa503f23aac/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + "hash": "4abdc5f9ad448c1ecbfae2974b820535d6bc6e7eef63babbab3d81cf46968c71", + "url": "https://files.pythonhosted.org/packages/ca/85/f82f8a92e31c7519410e2e1afdc630f28ec47490ce2c09a11c1a43cbb459/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_s390x.whl" }, { "algorithm": "sha256", - "hash": "9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9", - "url": "https://files.pythonhosted.org/packages/ec/96/5d9364e3342d69f3a045e1777bc47c85c383e6e9466d561b33fdb419d1f9/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "ae4a097991662cd4fff0ddc74e0fe7874f82e00042fa0ea00855645ed0c79598", + "url": "https://files.pythonhosted.org/packages/d3/05/71bfc5caa0abcc45aea1f6a4d50ac68e59605ddc7666fe8494f4cd229665/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" + }, + { + "algorithm": "sha256", + "hash": "aa2bb0b37202dca27175591f761108b5d34096ade1191ffe4808bdf6b1571488", + "url": "https://files.pythonhosted.org/packages/d5/fa/6a7e2a7c4b5451912b8c417732df79574354443592a88d616de03da66ae5/charset_normalizer-3.5.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "2f293479cce755c75f1697e87c409b7ae4c555c7dfecb6e988ad13abba943031", + "url": "https://files.pythonhosted.org/packages/d6/aa/a69a2028e8bd052476c245460ab19d7de595de084dd968f2d75cd50c3e25/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_riscv64.whl" + }, + { + "algorithm": "sha256", + "hash": "cee5dd7c6fb5dd52a0fe2a740f9bc6e3593f5f8b1788bde49de02086f30182b2", + "url": "https://files.pythonhosted.org/packages/d7/c7/9e48cee5c161fe24da823b61bf381921d77cb994a0a4de148e95018c1984/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "6117b84ea48435e5356dc737f5121485c30920ba43375fa7b434fd753df0eac3", + "url": "https://files.pythonhosted.org/packages/e5/3f/143b048436775b0f76ac3eec145c019e8173ccc2885c8f20319b996d5e83/charset_normalizer-3.5.1.tar.gz" + }, + { + "algorithm": "sha256", + "hash": "6e5e4d73d588ca5ed09df1b7dcd1b203d1df3c542e3f50d126c947d432b10731", + "url": "https://files.pythonhosted.org/packages/e7/80/b9348b5d3041209f98b4cdad7655766369233f1d533f4f4f7558e9717bec/charset_normalizer-3.5.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" + }, + { + "algorithm": "sha256", + "hash": "e6621fb2a4988d6e53eedc455e5903e2679f3967b8acb3d639f1b63c14a2e893", + "url": "https://files.pythonhosted.org/packages/e7/a0/47b18adeed31c8f16ba9700f32c1b18594cfa09f47eb672a488c273c22bf/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" + }, + { + "algorithm": "sha256", + "hash": "aa1099b956fb795e686d073568f6dc002a0bb89765ea6d5b055dd7d9bf1b116c", + "url": "https://files.pythonhosted.org/packages/f0/3e/48f4cd187b1c33189d86039e9cbe4f92c05454175504b44ff81806d4d1bf/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_armv7l.whl" + }, + { + "algorithm": "sha256", + "hash": "6ba32c4d2abf1d2fe7cf27d280f4cca5664233b0f885549c7761719eb977f486", + "url": "https://files.pythonhosted.org/packages/f5/28/c2028e7021fb89c6e56868ed0e387b8e9aa811abdd2ab3208d6578d2c930/charset_normalizer-3.5.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + }, + { + "algorithm": "sha256", + "hash": "b39b69b347e5e47a3b5b8cfc005c68c1ba347474e3960236c4944a8ecd174962", + "url": "https://files.pythonhosted.org/packages/f5/7b/ade0a122600319dfa0b1000ab0f9731c94a817904cf3c5de408c73a4ede7/charset_normalizer-3.5.1-cp37-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + }, + { + "algorithm": "sha256", + "hash": "366ec70f5547c640d3ce1985722490f23faf4eb5216a7eeba78277490e78dacb", + "url": "https://files.pythonhosted.org/packages/f5/e3/38b975422534a608f98c360e79c2f07c763d66dd4272300d45fb1fee54b0/charset_normalizer-3.5.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + }, + { + "algorithm": "sha256", + "hash": "96fef3e886d6a9874b14f27fc193fbdc69d5d8035783d86aa4e1cea594e695f9", + "url": "https://files.pythonhosted.org/packages/f6/0b/c5292a2462d69b7378ea89793bbb5b2b6fcf6f7dd6d1667f9619094ad553/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "aae2ee51122d3ae968a3837d97dc24a0aeebb0dea23694422cd172bd30017cd6", + "url": "https://files.pythonhosted.org/packages/f9/d2/d2aad6fe0dbb44b194bf3becb60f5a0ac48446ade999a47fe7bb41eb09a7/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_ppc64le.whl" + }, + { + "algorithm": "sha256", + "hash": "f298e218441525d3794428b4c8b8fb8662c6d3ea79925d4807ee6b9a96a3bca5", + "url": "https://files.pythonhosted.org/packages/fd/4c/9044135f42127630b6fa742feb51256353f6ab87a78f2fdd1de3de955a7f/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_riscv64.whl" } ], "project_name": "charset-normalizer", "requires_dists": [], "requires_python": ">=3.7", - "version": "3.4.9" + "version": "3.5.1" }, { "artifacts": [ @@ -1068,21 +1177,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", - "url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl" + "hash": "255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360", + "url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", - "url": "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz" + "hash": "ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34", + "url": "https://files.pythonhosted.org/packages/c7/0e/7fa0ef50764b67090eca4114772a2abf8b6148198475e54c660b97caeee6/click-8.5.0.tar.gz" } ], "project_name": "click", - "requires_dists": [ - "colorama; platform_system == \"Windows\"" - ], + "requires_dists": [], "requires_python": ">=3.10", - "version": "8.4.2" + "version": "8.5.0" }, { "artifacts": [ @@ -1248,153 +1355,153 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "084ef1af862eb07ec46d25f68689f2102a9fc0e05ce7b80f14f5fe51e4eef0f6", - "url": "https://files.pythonhosted.org/packages/ab/f8/614dc7e051418cfe53d55173c1e24c6b0085e89996fe90508c2fdf769aef/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl" + "hash": "804728ce710890870f3aaa344b2e161172d258d768ac139d02cfd9092d0d94e6", + "url": "https://files.pythonhosted.org/packages/51/cf/5b3f53a0b74d122f023476ede40ba5d3e70d5cf475f73b899740d26a4fb2/cryptography-50.0.1-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl" }, { "algorithm": "sha256", - "hash": "36d1709f992593689b45bda411498d62c6e365f2ca00b84657d4dadd24de16db", - "url": "https://files.pythonhosted.org/packages/09/41/3797cfaf69cae04a13ee78ebd83f0678d9c02b4779d21ce24445326f1a69/cryptography-49.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" + "hash": "2b34d76a652ea2b6faf777c35df230c5637842cd904e04f16230c3f9f03e4361", + "url": "https://files.pythonhosted.org/packages/0d/5c/13ea642e08e2544d0f5396122055f4820cfacb3203562197b5967125ea97/cryptography-50.0.1-cp39-abi3-manylinux_2_31_armv7l.whl" }, { "algorithm": "sha256", - "hash": "ec5e529fb80935c94fe7b729f9972b50e351a0e6b50aa294fd5cabb109fcc29a", - "url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl" + "hash": "be224a65493ec5b74a158ff22a5522ce4a5ca1e543c647a3a4730d4a09e5f959", + "url": "https://files.pythonhosted.org/packages/13/0e/b1f92e013228111413f2e6743948b80bc24dfd3c1b87ba98ceea16f5df89/cryptography-50.0.1-cp311-abi3-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "f89660a348f4f78a92366240a61404e337586ef7f5909a2fef59ca88ef505493", - "url": "https://files.pythonhosted.org/packages/1f/99/d1c90d6041656cc6ee229dc99cd67fd0cd5aec3c5f7d72fffc27cc750054/cryptography-49.0.0.tar.gz" + "hash": "5fe939deeb161024a6be98229c953b6591fef1f41214497a78fe793a244c017f", + "url": "https://files.pythonhosted.org/packages/14/9a/6d3a4d7852e22d657438b7bf51f66102c7d71c0e1fafeec652281d0403e5/cryptography-50.0.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "2afe9051da7ae7bd5905da5a949280c7d2bb75682e188f650a9d0f2756b834c6", - "url": "https://files.pythonhosted.org/packages/20/2c/0622f20ff02b2ef32558733443805dc82fd4c275be01b2d19d14676f3a1b/cryptography-49.0.0-cp311-abi3-manylinux_2_28_x86_64.whl" + "hash": "d63ae8f6481fec907ac0f588eee8a90aefde112c633131fe540e5711ddbb5a4e", + "url": "https://files.pythonhosted.org/packages/1d/e0/e786934472e3ac4ecdecc7b129a0ca1a2a40dffdafcf2c3ea9d4397f8def/cryptography-50.0.1-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl" }, { "algorithm": "sha256", - "hash": "9e82dcc8e56052715fb18b2429e3bca4823b1629136a2084fc45a9a5cecb9b64", - "url": "https://files.pythonhosted.org/packages/24/01/186c825898477d77e2324d5360fefe622ff1d8d1963ec0554e2cada8ec77/cryptography-49.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl" + "hash": "2a93d05e34d5f67fba6f891fe85d929999baa7195e853923ea6d7576c9e68c5e", + "url": "https://files.pythonhosted.org/packages/1f/ab/89e2b798d2c3925f82e2bb72d5979f3d2f6da2dd22ef4a8cd8b70d920039/cryptography-50.0.1-cp39-abi3-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "35b151772baff2c74cba7fa290ceaff4c3b11c0c881eb93eb5dbc05a7cfbba18", - "url": "https://files.pythonhosted.org/packages/2c/99/2d13299eb3dd27b02dcfaafcc91d6b5cb3329f7cbd6d8f51921acd566c1a/cryptography-49.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" + "hash": "4c4188f7c0cf655be5c06342b817ed0f9595b69ffa2b12026e5353eed29dea88", + "url": "https://files.pythonhosted.org/packages/27/3a/3c5f80daa4dcd47323c7af8a2fcb90de27a33564d4fcac69846c0972691a/cryptography-50.0.1-cp39-abi3-manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "f78ff2c9ed8dc2d036b0f4d640e22522213d047c1b14e61205a7e55c80a494d4", - "url": "https://files.pythonhosted.org/packages/3d/df/40577043ca124e17012f408ddddaeb213b856336ac82ddb3bc915f39e29f/cryptography-49.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" + "hash": "359e62deae718bce96170e223fdcb6357e4fbd3bb7a3a75f4430763532560e49", + "url": "https://files.pythonhosted.org/packages/29/ba/042ca458b8c64348c768284b5d23e69b92ed53d057ab779fee628564676d/cryptography-50.0.1-cp311-abi3-manylinux_2_31_armv7l.whl" }, { "algorithm": "sha256", - "hash": "53ecee2e23f7169b6117e99fc8a944e5e50f79e69758a83b52a00cb98ab2b2d2", - "url": "https://files.pythonhosted.org/packages/4a/91/01ce7303a4579e6d3a6abef01bd322848e9ea7a219adcabc5048b9033571/cryptography-49.0.0-cp311-abi3-manylinux_2_28_aarch64.whl" + "hash": "e2ca8fd1b6b4b82a1c4cb02841d0837e3c12336c2e24b520ab8ab3b969733d8f", + "url": "https://files.pythonhosted.org/packages/39/3b/e96c1ef71edef71057c7e3c3d982ce8fda554e0c52d0cc19c18845cde3eb/cryptography-50.0.1-cp311-abi3-manylinux_2_34_aarch64.whl" }, { "algorithm": "sha256", - "hash": "b87e65d263b3e5d3bb92a57e2a6638e2f31110fa7aa890c7b2dbba42248d0a3f", - "url": "https://files.pythonhosted.org/packages/4f/01/339573cf1023163a400b0b5d16f6d507de413b9f60be6fd1b77feeaf6737/cryptography-49.0.0-cp311-abi3-musllinux_1_2_aarch64.whl" + "hash": "5fe002589592ed749ce77fe0695fcbd3500dd61d7d6db5858a7544c612fa8e45", + "url": "https://files.pythonhosted.org/packages/55/32/38c0d344b98c06d34b5df8946565a9c0d6dbf32c8e0730a7f05f0a3c6cab/cryptography-50.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "2eda353d8a27bcbcaa4cbed18994a74ab4d19a2ca897db188ea269ab9b71419b", - "url": "https://files.pythonhosted.org/packages/62/99/a2c95cf8293f07491e9e27c20cc4dcd18176d944e674679adeb1d0173fd6/cryptography-49.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl" + "hash": "ff838d62ec1bfce4f9ba7fa16f4a7b554cd8d0c299e6be37502161a660c84eef", + "url": "https://files.pythonhosted.org/packages/57/26/e6d4fc8512a51a5f9ee7bfdbfb853bce1197087df40c9ad993ad370b846f/cryptography-50.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" }, { "algorithm": "sha256", - "hash": "fc1e275c2f1d97b1a6450b8b0ea3ebfa6e087a611c2b26cb2404d48588abab7b", - "url": "https://files.pythonhosted.org/packages/63/d3/4a83af35d65e3fad632c926fad684c193ea4398569ccb0bbbc7fe8f5dc9a/cryptography-49.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl" + "hash": "05ba322c4da95b262a212c345af888ef2c37c88c0509756ea00a0e6d68850f23", + "url": "https://files.pythonhosted.org/packages/5e/a5/9ec7e81e8526c0d7a387d73386b2daed3f39e10d81a85930bd1b6bfba65c/cryptography-50.0.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" }, { "algorithm": "sha256", - "hash": "6fc361c34fb6aac015ce19435876635e5c6d21db31998b0920f675f131e043b8", - "url": "https://files.pythonhosted.org/packages/67/d0/a5fcd3515f0bae49a7b6d0413cc1bdccdcc1fc0047037a0d480642cdc5d6/cryptography-49.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl" + "hash": "fd3718b960d0b5dd213cdf03f3bcb7000e69dda0de8b956061947ff6bcff5558", + "url": "https://files.pythonhosted.org/packages/63/8e/f1f955e0921dd2b6d22eae7e8d24a4c4b638d10735ffbf6a71f99eb0fcb8/cryptography-50.0.1-cp39-abi3-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "8c25ceb16df5b9435f3f6a9829204985b0e0cbee3b48aacd432c7d2c850b44d9", - "url": "https://files.pythonhosted.org/packages/6c/72/3e798c064bc39e471008075d0f9bc9daf77a80879c092e4a8e170c585ed4/cryptography-49.0.0-cp39-abi3-manylinux_2_31_armv7l.whl" + "hash": "2ebbfb0f1fed745e91796e3e1080a1440423fdae8ece1b995a1d80883a409054", + "url": "https://files.pythonhosted.org/packages/6e/2b/214cf0cf93db9628c3c20c896b229f327f6fb1b20e4b3743d8ad3f00af8b/cryptography-50.0.1-cp39-abi3-manylinux_2_28_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "67e1d20ad9ef3a563c59ef22e7a8a0b8210bd26604369ea4a30a7c66aefe504e", - "url": "https://files.pythonhosted.org/packages/6c/a0/db537264e234f7273a73ec020873d6d6b39dfd8a53db78b550ca8320440e/cryptography-49.0.0-cp39-abi3-musllinux_1_2_aarch64.whl" + "hash": "fb4b9672d389c738b175c4166e78310f8a70358886aacd9173ee03a85ffdc671", + "url": "https://files.pythonhosted.org/packages/73/35/5c3717edf9e68a0550ce04e28eab493fe545eccd81742af03f6a75fe260b/cryptography-50.0.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "ccac2bfebc306b862133e3bb71f3f6ee8bb525240089b2d952e4144b3a6d5da7", - "url": "https://files.pythonhosted.org/packages/6d/88/05563c7fe2e914e87d1a536d06fe83e66b4e1d95cb593e05aea375531da8/cryptography-49.0.0-cp311-abi3-manylinux_2_34_aarch64.whl" + "hash": "9ebcdd5519be9b652a46f507817a74591774fc3d6923ac364e4dfa64e36b291b", + "url": "https://files.pythonhosted.org/packages/7e/22/c3654cccc856e9d682817b04ac3ee79731cb09ca6f95996a95c904de2883/cryptography-50.0.1-cp311-abi3-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "66ec79c3904820572d7e987abdf304281f141d37ad9a489b8e97066e7b9b6459", - "url": "https://files.pythonhosted.org/packages/71/fd/577302e213a1be9468f92d1afef66fcf1ef83d516819d9992ca547f592bd/cryptography-49.0.0-cp311-abi3-musllinux_1_2_x86_64.whl" + "hash": "e22dfed744bd4002e909464cb23d2f0b05c6f3113a79ef2e9864a53db737c733", + "url": "https://files.pythonhosted.org/packages/7e/3c/0e77bd5ffcf078e9dd27d3074aad6c030d9b10d0bf69329d573c927a188c/cryptography-50.0.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" }, { "algorithm": "sha256", - "hash": "42b0684e0e40cf26122427802486f6d93aea593612603a94fbf260c7eb1e9c1b", - "url": "https://files.pythonhosted.org/packages/93/77/8df9eb486495979bccecd1062e2eaf435250e84437040295b57d09048b0b/cryptography-49.0.0-cp39-abi3-musllinux_1_2_x86_64.whl" + "hash": "ca83d00d9e69cd5eb63f2e69c3a5a59e0cecae5ae14c6ae0b35830fe3b37bad0", + "url": "https://files.pythonhosted.org/packages/84/a9/ee16a903f13755e914d1eecc482fe64d1f10761c3960e5d8fa6837377aff/cryptography-50.0.1-cp39-abi3-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "b47db11c2c3525083296069b98ac5221907455e989ae0c2e3008bde851921615", - "url": "https://files.pythonhosted.org/packages/94/64/2923570ac1c0bd3a737aa366ac3abbbbde273042308b8cde95e2364a6e6a/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl" + "hash": "01f41478cf33fc605a6a089cd56d28b45c6c0b45a1928b61797f2621a04bac71", + "url": "https://files.pythonhosted.org/packages/84/d5/7d1fe1cb93f91c428093ff234e128c89ba8ea61a6f26aab406081f9b996e/cryptography-50.0.1-cp39-abi3-manylinux_2_34_aarch64.whl" }, { "algorithm": "sha256", - "hash": "966fe0e9c67490071f14c0d2b1cb2dfb3023c5ce39457343931415f08382f2db", - "url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl" + "hash": "51afcfceb15597cf2635068e4ac9a56b2abde622edde17f37d85fd7b5306497a", + "url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl" }, { "algorithm": "sha256", - "hash": "2400ef9c9e2299a25614eb1dea3db54a69b1349efd043bfac9c67630d136df36", - "url": "https://files.pythonhosted.org/packages/a0/84/84fe36f19caf857d61cb7fc9c63035a47ffabd84ea12d1d393148efa3615/cryptography-49.0.0-cp39-abi3-manylinux_2_34_x86_64.whl" + "hash": "9dde0a357190eb3b1da1bb9ab750e9c85cba82ca5977aa0836cbb94e92611239", + "url": "https://files.pythonhosted.org/packages/8c/eb/5d7124083e8d8cda8f5b348f544b71ad6f707ad63193758ef4d8e569da02/cryptography-50.0.1-cp39-abi3-manylinux_2_34_x86_64.whl" }, { "algorithm": "sha256", - "hash": "0b82e28ee398a386f0807bba7884d30f25218855690f45115831bcce5d90822c", - "url": "https://files.pythonhosted.org/packages/a3/5b/c5246635d5fd3b64e0d45ae10e99fd32fe9676a79915ccfe5a61ba9af1a5/cryptography-49.0.0-cp311-abi3-manylinux_2_31_armv7l.whl" + "hash": "53e279950892dc102c6b4e52af03ae5ea92fac572a1ddab78ca73a997f62b69f", + "url": "https://files.pythonhosted.org/packages/90/34/9ce9a62ed9dc82ca9fd6a34445b6904af56e5f38b3eae2ed32e49c36053d/cryptography-50.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" }, { "algorithm": "sha256", - "hash": "0f21641cf4b30fca7aee061ced0ec7ad7b073518088b7c9969a297c0ae796c69", - "url": "https://files.pythonhosted.org/packages/a5/4d/9c0cd02f95e2602dd5e563da149ee0830abef3537be8b34dc56281ebe27a/cryptography-49.0.0-cp39-abi3-manylinux_2_28_aarch64.whl" + "hash": "b8f852c65863251b9e3a1b8c150ce21e59b522dbb6a7d4bc80e680d38388e986", + "url": "https://files.pythonhosted.org/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "cbc77da8c523d5abd028635ba850a6966fcee2c82e2bf65a41d1d8afe0f98be9", - "url": "https://files.pythonhosted.org/packages/a9/3c/f3ad17eecc1a57b0ba236dc01f90e783c51f4a2f35f64777cc4f47a184b2/cryptography-49.0.0-cp311-abi3-manylinux_2_34_x86_64.whl" + "hash": "5dd9bda1c12b4162f6ff568eeb5e0ff956c28d14406e875cfe8a63a2d414ff20", + "url": "https://files.pythonhosted.org/packages/bb/ad/5d6702db60b1e40b41ef513b6967ff5848f307d50f8449baf1634f5908f1/cryptography-50.0.1.tar.gz" }, { "algorithm": "sha256", - "hash": "6f2debedf9ca60cf1d5bd466475638af5130f89965605cd818484d19987d3a21", - "url": "https://files.pythonhosted.org/packages/b8/7b/62cbbab75d0659865bf0273790031544a0b16c8072d258f9428dcd8190dc/cryptography-49.0.0-cp39-abi3-manylinux_2_28_x86_64.whl" + "hash": "9cb3cb952cf5a8abd50c782a98a89d71699715e802fe349704b47f2425b42a94", + "url": "https://files.pythonhosted.org/packages/c7/27/8d207af749c453ee17ea087340b3f2b4adef75aadd1d277b1b129bdda84e/cryptography-50.0.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "d0527ce944105f257f605a827d6ebead966c752038b6e8656abb9c5edee6fc68", - "url": "https://files.pythonhosted.org/packages/c4/b6/d7696e4e890d6ae1469935164c9e5215c557671cb78d6e3f458ccceaa632/cryptography-49.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl" + "hash": "407fe2b6db00939c05c0e945e9914238f2f0a430974839429dafc82b1ee6bee5", + "url": "https://files.pythonhosted.org/packages/d6/51/3f9701867a46b6c1740c9b52fc4d3bed6cbdcfedcc9b6e64305c07f39cff/cryptography-50.0.1-cp39-abi3-manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "c83782480a4a9da4d0feb51950131ba32e12e70813848b3343f6e18c28a66838", - "url": "https://files.pythonhosted.org/packages/d6/a7/f9dac0ab7f80368c56993a7bf638ef9935f825c91902798481fac0898138/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl" + "hash": "fc3ed7ebd2a8c96f5b166de0ab9b624996bef3b07bbeb19364dfb78222c22c80", + "url": "https://files.pythonhosted.org/packages/dd/04/557fc5ead96a829e0bc812a3b9dc4a52a2f27e4f7f5950da7ff27653a805/cryptography-50.0.1-cp39-abi3-manylinux_2_34_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "b39efa323140595abd3ecca8529d321ae50f55f3aa3ba9cc81ea56a6011953d5", - "url": "https://files.pythonhosted.org/packages/d7/70/2ba3769dd0ae167e2f33dfa9592d45db6ff9a61d62ca1a5b3d1bdd09068f/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl" + "hash": "51593d180cf6d179bde5c5d065bed81386b1f381656ae7d042b7ffc87a9895ad", + "url": "https://files.pythonhosted.org/packages/e1/1b/82f0f0d8858d4432be1af790477edf62aef90324041aa07c57e57bef1af7/cryptography-50.0.1-cp311-abi3-manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "0e959b578856a3924bc0cbb710fc12c387b9412a951389f3ca61704a9e25f325", - "url": "https://files.pythonhosted.org/packages/e6/8b/43011f7ebe515a8aa20d61f290a326cd890c2e738e16e59eaff8d9c3a412/cryptography-49.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" + "hash": "76de83fbd91ac49c0feaaa983d0748fd7a53176afac5fb3bf7478d244f0eb527", + "url": "https://files.pythonhosted.org/packages/e3/38/45abd72ef63f2e7d0754a6cacf97bd8b69512ace7f6130d24c39ece65da2/cryptography-50.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "28d8b15e6275f12c8a207dc309dfa957903c927d08d0cc937ee3f63f200693cc", - "url": "https://files.pythonhosted.org/packages/f0/ee/6fca21d1ac73e06f8bef71940abfd4d2f6472b4bca284d770f32bd4086f6/cryptography-49.0.0-cp39-abi3-manylinux_2_34_aarch64.whl" + "hash": "e74591e283fe6eb956416c929eb58262a719fe0311fd9054c62c3350ed8760d8", + "url": "https://files.pythonhosted.org/packages/e6/de/d3cdc2815697aae84126cbd6a030ca7b6b452e28a88b501b836bd3aa7a86/cryptography-50.0.1-cp311-abi3-manylinux_2_28_aarch64.whl" } ], "project_name": "cryptography", @@ -1404,7 +1511,7 @@ "typing-extensions>=4.13.2; python_full_version < \"3.11\"" ], "requires_python": "!=3.9.0,!=3.9.1,>=3.9", - "version": "49.0.0" + "version": "50.0.1" }, { "artifacts": [ @@ -1527,13 +1634,13 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "bc22396093cb4119ff7007776be6a5348a613ccd42eeb0f9519853a6efcbcabe", - "url": "https://files.pythonhosted.org/packages/c3/1c/febe9acf1b4f0d67603b231c28d6d17d647d68c90c1963fecdeb64046d6d/eventlet-0.41.0-py3-none-any.whl" + "hash": "6cae50e67fe6ae8bb7013e7fd4d8e0d0d20aeb9b3259b93f023c93eb6749631f", + "url": "https://files.pythonhosted.org/packages/23/75/9681fa59c4b27d9e34e8be682d2fff3f5be87bf6552477f9a5d395a068c3/eventlet-0.41.2-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "35df85f0ccd3e73effb6fd9f1ceae46b500b966c7da1817289c323a307bd397b", - "url": "https://files.pythonhosted.org/packages/d3/90/32772ae7c9897554c56b9367b67478a3dc89c70d9b4d12e241746f6fdae3/eventlet-0.41.0.tar.gz" + "hash": "721b86b77fca33a735598292022ac6feef99747bf48f52defdada6b572acd5af", + "url": "https://files.pythonhosted.org/packages/eb/e8/6a3a23a3b85ed129b21309c6eca873d833855e63879cd72b9dac20d9b76a/eventlet-0.41.2.tar.gz" } ], "project_name": "eventlet", @@ -1549,7 +1656,7 @@ "twine; extra == \"dev\"" ], "requires_python": ">=3.10", - "version": "0.41.0" + "version": "0.41.2" }, { "artifacts": [ @@ -1596,19 +1703,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "987db6f789a3a2a59f55081801b2b3697cb97e2a736b5f1a9e99b559285fbc51", - "url": "https://files.pythonhosted.org/packages/60/02/be4a57b60c7149b55b9e3b3c13f609cd8eb5307c751f22bd8fb8d262e75b/filelock-3.29.7-py3-none-any.whl" + "hash": "22e58ca3b1ae3b98993b762d7338367ae64fe50252bf78d59da3bfebcdf1cedd", + "url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "5b481979797ae69e72f0b389d89a80bdd585c260c5b3f1fb9c0a5ba9bb3f195d", - "url": "https://files.pythonhosted.org/packages/35/94/00f2059e4835eace3ae8fde680b932c496f8ec7bdc99168dfa53fb2e6b79/filelock-3.29.7.tar.gz" + "hash": "2bde2e4cf732e0153406d8a7bc80620ecf5e621fe0d25e41143c4e3b4733ff30", + "url": "https://files.pythonhosted.org/packages/6d/30/03b03951873a1a0ffc7e8ca0e10c15597b59e8d0e39260704cd2ea087bc4/filelock-3.32.4.tar.gz" } ], "project_name": "filelock", "requires_dists": [], "requires_python": ">=3.10", - "version": "3.29.7" + "version": "3.32.4" }, { "artifacts": [ @@ -1658,6 +1765,118 @@ "requires_python": ">=3.10", "version": "3.3.0" }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "2d2c9c23cf68e2d4565505f8b5cd31b269259e1fbfb57bcc3d4d1cd34ee274d1", + "url": "https://files.pythonhosted.org/packages/6d/16/f06ee39db14422d5f749cdcfeb7b8a7b426e087dace9d2c8675633fe6eb4/gevent-26.8.0-cp312-cp312-musllinux_1_2_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "946848924dd80d29184367c0c9a4fc809411d17afbe157128687df8d7d838560", + "url": "https://files.pythonhosted.org/packages/05/59/967712d5cbabb82fb0619914b82266d0150322966376430df4c73dfbfda4/gevent-26.8.0-cp312-cp312-musllinux_1_2_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "be8810be489005bee66d2c6ad1025bfa4f5cfc46f50c775876b35ffe2acf7e3b", + "url": "https://files.pythonhosted.org/packages/0f/5d/a5e9b1dee7395c68a2d137eb31154cbf5357a54eab19595273145dc69ebf/gevent-26.8.0-cp311-cp311-musllinux_1_2_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "108614bd47ec714ed93d141965bac8c17e44bbae08e238696da6261f013caa83", + "url": "https://files.pythonhosted.org/packages/14/99/b82608b486cd9f79a4ebb480779900e7bb7dc095dc9217991fdb173b0084/gevent-26.8.0-cp312-cp312-manylinux_2_28_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "848c2d1441e9fc5ff5b32aa347a2de561ac3d19abda3d9d61cd0e98aaeb9d8d4", + "url": "https://files.pythonhosted.org/packages/19/ec/739e90f26a7d98fd8f70cf737e7720cb872bc9cd61b2b3954d179f24801d/gevent-26.8.0-cp311-cp311-manylinux_2_28_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "b564b959a5391bcfa607bf991a6c368fc0cc7f12730ab0d21777839f643f8285", + "url": "https://files.pythonhosted.org/packages/1f/1d/35af72b6cdc2e48017d92cb44a25623ca32515aef805727eddffb8c60025/gevent-26.8.0-cp311-cp311-manylinux_2_28_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "5fa5728333b744f5d10bd6fa5474616c7a1a76da81044cfa3d2d0fae2d245ba2", + "url": "https://files.pythonhosted.org/packages/29/20/865715d8b4d723253ef09292358027aa5eae02ca0710aee4664d5b477c4e/gevent-26.8.0-cp310-cp310-musllinux_1_2_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "8e2be34e41557387a422e78c0124e2b90a4df9f1cc87c891503bf34a95ae1ce5", + "url": "https://files.pythonhosted.org/packages/4f/f4/a49ac5d1b508dfcc9af2d08435d9c2c71fdc12d44fe75156c6441f6127de/gevent-26.8.0-cp312-cp312-manylinux_2_28_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "94544a0f5a1d14b711cd630eab0581a53f3ea89370f8963df9ced62ec6552ca9", + "url": "https://files.pythonhosted.org/packages/56/94/a5d38541f3a9fd77aa8defe8bb66698176be959cebda9c2be00fc5ad9e63/gevent-26.8.0-cp312-cp312-macosx_11_0_universal2.whl" + }, + { + "algorithm": "sha256", + "hash": "102087dab60f43f52be74e4be7e42345de27d1968707ded31c785e91d41978b1", + "url": "https://files.pythonhosted.org/packages/ae/9b/cfbc57b758d0435889be2726a5ae1570e6563a24976f4b62e5ecf81b3c3d/gevent-26.8.0-cp312-cp312-manylinux_2_28_ppc64le.whl" + }, + { + "algorithm": "sha256", + "hash": "0b7684220f4cab1dda07143f4494c6883934bf4378014ce860ccba45d252d82e", + "url": "https://files.pythonhosted.org/packages/b0/fb/c258724be7d5c63812961a7448a2f02be84ba71f272021b9a608aceed685/gevent-26.8.0-cp311-cp311-manylinux_2_28_ppc64le.whl" + }, + { + "algorithm": "sha256", + "hash": "8e22ce9c9b2fbe498c00665cfa4a598ce8d04dec8ea60047c0c4e2e6ce4ee686", + "url": "https://files.pythonhosted.org/packages/b7/ce/605c5a38e50b3043f2e8c6c0885faf8b37fdaeea3cb714e840db19bf5bda/gevent-26.8.0-cp310-cp310-manylinux_2_28_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "96039f41bbde6dcd72559e5ffbd408a04f46774b47d991d4cf032da8fa79e5a0", + "url": "https://files.pythonhosted.org/packages/b8/eb/5f2db8013f1a4a6df2c23201f384a066f13ff5764a9f62a608c8a50ac8cc/gevent-26.8.0.tar.gz" + }, + { + "algorithm": "sha256", + "hash": "c2730709f8e894c167415e1d3752d63e6ed40f28b60bdb2ba7bdf973fa29296a", + "url": "https://files.pythonhosted.org/packages/c7/2a/82ab6a41a064792e3df4a9c03e1e90ccf622f8f3352d9a22c1e03e2f159e/gevent-26.8.0-cp312-cp312-manylinux_2_28_s390x.whl" + }, + { + "algorithm": "sha256", + "hash": "304a486b1833a83a028c8c02bbdff62867dc2ee1c6ba654d32d7340ab7b19afb", + "url": "https://files.pythonhosted.org/packages/c9/35/df8f0e37975a4a8d832542316f7abc5107fa3cf516201fd40a7588446b0a/gevent-26.8.0-cp311-cp311-manylinux_2_28_s390x.whl" + }, + { + "algorithm": "sha256", + "hash": "5a2fae0fe891f7975cc0a5e4ac3b29bb0fc569a271de4b2b8fdb73dccbf7bc8e", + "url": "https://files.pythonhosted.org/packages/de/cc/d4eb977aed853f2fab530b46de99d7ce6ff3a0993ad56251c0feee5db837/gevent-26.8.0-cp311-cp311-musllinux_1_2_aarch64.whl" + } + ], + "project_name": "gevent", + "requires_dists": [ + "cffi>=2.1.1; platform_python_implementation == \"CPython\" and extra == \"recommended\"", + "cffi>=2.1.1; platform_python_implementation == \"CPython\" and extra == \"test\"", + "cffi>=2.1.1; platform_python_implementation == \"CPython\" and sys_platform == \"win32\"", + "coverage<7.13,>=5.0; sys_platform != \"win32\" and extra == \"test\"", + "dnspython<2.0,>=1.16.0; python_version < \"3.10\" and extra == \"dnspython\"", + "dnspython<2.0,>=1.16.0; python_version < \"3.10\" and extra == \"recommended\"", + "dnspython<2.0,>=1.16.0; python_version < \"3.10\" and extra == \"test\"", + "furo; extra == \"docs\"", + "greenlet>=3.2.2; platform_python_implementation == \"CPython\"", + "idna; python_version < \"3.10\" and extra == \"dnspython\"", + "idna; python_version < \"3.10\" and extra == \"recommended\"", + "idna; python_version < \"3.10\" and extra == \"test\"", + "objgraph; extra == \"test\"", + "psutil>=6.0.0; (sys_platform != \"win32\" or platform_python_implementation == \"CPython\") and extra == \"monitor\"", + "psutil>=6.0.0; (sys_platform != \"win32\" or platform_python_implementation == \"CPython\") and extra == \"recommended\"", + "psutil>=6.0.0; (sys_platform != \"win32\" or platform_python_implementation == \"CPython\") and extra == \"test\"", + "repoze.sphinx.autointerface; extra == \"docs\"", + "requests; extra == \"test\"", + "sphinx; extra == \"docs\"", + "sphinxcontrib-programoutput; extra == \"docs\"", + "zope.event", + "zope.interface", + "zope.schema; extra == \"docs\"" + ], + "requires_python": ">=3.10", + "version": "26.8.0" + }, { "artifacts": [ { @@ -1682,17 +1901,18 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "d5b29685708f3c80a56db040b665bfd69492c8e150b5848532af8013b686c5a4", - "url": "https://files.pythonhosted.org/packages/f8/11/1232bb1ba52a230f20ff08e1b3df7cd9d43a71b61cc0a1c37941064fe4c7/gitpython-3.1.51-py3-none-any.whl" + "hash": "8ab28c9da863cdd9e7d7694ec46cf3e6c9a12d8a30a1acd3447aec11975d530c", + "url": "https://files.pythonhosted.org/packages/6f/5e/49cc172da4d0578644ba37cec5cb365b1fefc603b26edea9bcac1c7f830a/gitpython-3.1.61-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "22c9c94bb6b0b9f3c7157c684fece45a414cea204586b600beae6cd4570dcd6d", - "url": "https://files.pythonhosted.org/packages/59/30/a8a0c15f9480dc91b5b7f11ebd26105e5f80898d7ff02da197fef35d8395/gitpython-3.1.51.tar.gz" + "hash": "f51c24d8c0f733a195447385f5774a5dfe8767f5acfd7994a33755644c6ecc95", + "url": "https://files.pythonhosted.org/packages/6f/61/3285044215fb596bf093e39ccb96ece0a1076a8ca57a61e069a6a33cdb1b/gitpython-3.1.61.tar.gz" } ], "project_name": "gitpython", "requires_dists": [ + "basedpyright==1.39.9; (python_version >= \"3.9\" and sys_platform != \"cygwin\") and extra == \"test\"", "coverage[toml]; extra == \"test\"", "ddt!=1.4.3,>=1.1.1; extra == \"test\"", "gitdb<5,>=4.0.1", @@ -1711,7 +1931,7 @@ "typing-extensions>=3.10.0.2; python_version < \"3.10\"" ], "requires_python": ">=3.7", - "version": "3.1.51" + "version": "3.1.61" }, { "artifacts": [ @@ -1750,128 +1970,128 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "6b1b0eed82364b0e32c4ea0f221452d33e6bb17ae094d9f72aed9851812747ea", - "url": "https://files.pythonhosted.org/packages/ae/73/be55392074c60fc37655ca40fa6022457bfbf6718e9e342a7b0b41f96dd2/greenlet-3.5.3-cp312-cp312-musllinux_1_2_x86_64.whl" + "hash": "12e2ee66c2aba86133f10fd99d6a8856c6d351ffb7be0e4d52ef2cc5fbb705b2", + "url": "https://files.pythonhosted.org/packages/b8/d7/734e5f198888876b42d7616ff6644c075baf6b8a2412deadd6b0e1b8b20c/greenlet-3.5.5-cp312-cp312-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "8bdb43e1a1d1873721acab2be99c5befd4d2044ddfd52e4d610801019880a702", - "url": "https://files.pythonhosted.org/packages/03/79/fb76edb218fe6735ab0edeba176c7ab80df9618f7c02ce4208979f3ae7db/greenlet-3.5.3-cp310-cp310-musllinux_1_2_x86_64.whl" + "hash": "816230f469381ad0a43abc9fa8dda5a699e32fb78958dde32ded93213b70a667", + "url": "https://files.pythonhosted.org/packages/07/67/07ecd6d85c0f253363cbc4ac9e7dd048ca571a267fbccfea084d6009ac3b/greenlet-3.5.5-cp310-cp310-macosx_11_0_universal2.whl" }, { "algorithm": "sha256", - "hash": "d27c0c653a60d9535f690226474a5cc1036a8b0d7b57504d1c4f89c44a07a80c", - "url": "https://files.pythonhosted.org/packages/07/7f/e327d912239ec4b3b49999e3967389bcf1ee8722b9ee9194d2752ecd558a/greenlet-3.5.3-cp311-cp311-manylinux_2_39_riscv64.whl" + "hash": "adb4bae02e91a8e863e48b177e4014bdcac8a6b5e047ea1df687a61534b85e6c", + "url": "https://files.pythonhosted.org/packages/0b/d8/7cc97c142388aef03f622e001c572c4f84e9252a439549d483f555771970/greenlet-3.5.5.tar.gz" }, { "algorithm": "sha256", - "hash": "483d08c11181c83a6ce1a7a61df0f624a208ec40817a3bb2302714592eee4f04", - "url": "https://files.pythonhosted.org/packages/0a/29/be9f43ed61677a5759b38c8a9389248133c8c731bbfc0574ecdff66c99fc/greenlet-3.5.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl" + "hash": "c69bed34470abfcd456984fdadaa18e62169af4480335c45f3c32d1d9c12e638", + "url": "https://files.pythonhosted.org/packages/18/5e/58c561efde575c4ca070030e2e0513e8d1b07b76d8a2d84a9bcef1becd42/greenlet-3.5.5-cp310-cp310-manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "7ef56fe650f50575bf843acde967b9c567687f3c22340941a899b7bc56e956a8", - "url": "https://files.pythonhosted.org/packages/2a/7b/ad04e9d1337fc04965dc9fc616b6a72cb65a24b800a014c011ec812f5489/greenlet-3.5.3-cp311-cp311-musllinux_1_2_aarch64.whl" + "hash": "a5433cf291e0ef9114bd14d0d824db6e5e4a43033234bca48181a9597acca07b", + "url": "https://files.pythonhosted.org/packages/24/35/426733bc24247ee17bb76df90f550c299ff5f8572b2bdd7cacb5c53fd994/greenlet-3.5.5-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "0f6ff50ff8dbd51fae9b37f4101648b04ea0df19b3f50ab2beb5061e7716a5c8", - "url": "https://files.pythonhosted.org/packages/2e/8c/231ca675b0df779816950ca66b40b1fa14dbff4a0ed9814a9a29ec399140/greenlet-3.5.3-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl" + "hash": "49520f0c95a48b42cf55414b8e8479beb274ea70431afc33e3f79903c71f4380", + "url": "https://files.pythonhosted.org/packages/2e/7e/9ecd0285e3153532ae07aeb88063c43c72b4221cf0d4d123b02f3682e3ff/greenlet-3.5.5-cp312-cp312-macosx_11_0_universal2.whl" }, { "algorithm": "sha256", - "hash": "87142215824be6ac05e2e8e2786eec307ccbc27c36723c3881959df654af6861", - "url": "https://files.pythonhosted.org/packages/37/87/b4d095775a3fb1bcafbb483fc206b27ebb785724c83051447737085dc54e/greenlet-3.5.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl" + "hash": "55272212cbc5f43d1d723725ab931f1939969b7e9523882ca58b55061769d053", + "url": "https://files.pythonhosted.org/packages/35/73/60e4bbcc89252037b18087f2ec16405d5b2d5be42dde191bbf3667e96102/greenlet-3.5.5-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "aca9b4ce85b152b5524ef7d88170efdff80dc0032aa8b75f9aaf7f3479ea95b4", - "url": "https://files.pythonhosted.org/packages/51/58/5404031044f55afad7aad1aff8be3f22b1bed03e237cfeabbc7e5c8cfde0/greenlet-3.5.3-cp311-cp311-macosx_11_0_universal2.whl" + "hash": "abc8bc8d9f935cd685457545b6a53863a877fdc12c2c0f5ee9beee18d9db139c", + "url": "https://files.pythonhosted.org/packages/39/82/5c873dbb4fb001d22fbbd50e80d4c1b0181ddae106856132160f84b94e88/greenlet-3.5.5-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl" }, { "algorithm": "sha256", - "hash": "719757059f5a53fd0dde23f78cffeafcdd97b21c850ddb7ca684a3c1a1f122e2", - "url": "https://files.pythonhosted.org/packages/5d/6e/4c37d51a2b7f82d2ff11bb6b5f7d766d9a011726624af255e843727627a3/greenlet-3.5.3-cp312-cp312-macosx_11_0_universal2.whl" + "hash": "523bb8e27614d77101ea7a8cf59f8d91219b72d5c29f6a038c92b50828bfa8d0", + "url": "https://files.pythonhosted.org/packages/3c/78/52de4f7ac9152ad1dbc8f437895c1e573d30ee1e1427e0f91a280e2417b6/greenlet-3.5.5-cp310-cp310-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "8540f1e6205bd13ca0ce685581037219ca54a1b41a0a15d228c6c9b8ad5903d7", - "url": "https://files.pythonhosted.org/packages/78/2b/28ed29463522fdbe4c15b1f63922041626a7478316b34ab4adda3f0a4aba/greenlet-3.5.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl" + "hash": "6d9b454c5fc48aeaa7c4337813dbf513a6870468e426438a04d922c6d0fe63db", + "url": "https://files.pythonhosted.org/packages/3e/4a/92fc51d5d35912f4f06eec037ba347985defd0be47463a010a325634d9d2/greenlet-3.5.5-cp311-cp311-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "efa9f765dd09f9d0cdac651ffdf631ee59ec5dc6ee7a73e0c012ba9c52fbdf5b", - "url": "https://files.pythonhosted.org/packages/7a/73/815dd90131c1b71ebdf53dbc7c276cafec2a1173b97559f97aba72724a87/greenlet-3.5.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl" + "hash": "be63afcbbccfad3dd95a1ba12ada84dab2ef32031973d80b5b92df67fa763a61", + "url": "https://files.pythonhosted.org/packages/4e/a3/07297917485ee2ca85bc3c8dc6ed85ad3fffcf424047fba62671dba68e97/greenlet-3.5.5-cp311-cp311-macosx_11_0_universal2.whl" }, { "algorithm": "sha256", - "hash": "37bf9c538f5ae6e63d643f88dec37c0c83bdf0e2ebc62961dedcf458822f7b71", - "url": "https://files.pythonhosted.org/packages/81/fe/dd97c483a3ff82849196ccd07851600edd3ac9de74669ca8a6022ada9ea1/greenlet-3.5.3-cp310-cp310-manylinux_2_39_riscv64.whl" + "hash": "74cc6df89ec5302337adc9cf096221cbed2510fd444b0e0f1586cf0470740864", + "url": "https://files.pythonhosted.org/packages/51/2d/f2c928218ac52f26d7a2c188c171d1b7e728b23782cb3347e7b4fce1493a/greenlet-3.5.5-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "215275b1b49320987352e6c1b054acca0064f965a2c66992bed9a6f7d913f149", - "url": "https://files.pythonhosted.org/packages/8a/70/7559b609683650fa2b95b8ab84b4ab0b26556a635d19675e12aa832d826d/greenlet-3.5.3-cp312-cp312-musllinux_1_2_aarch64.whl" + "hash": "9ff00e12102358292087274dfb1669132387ff6e7920ebf9d85f4826ce0d3a56", + "url": "https://files.pythonhosted.org/packages/51/91/00b3c0566316c6f383ea16ee05388ec4f57f6e0afa49e72ae471eda8c47f/greenlet-3.5.5-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "af4923b3096e26a36d7e9cf24ab88083a20f97d191e3b97f253731ce9b41b28c", - "url": "https://files.pythonhosted.org/packages/8e/ac/e5fee13cbbd0e8de312d9a146584b8a51891c68847330ef9dc8b5109d23f/greenlet-3.5.3-cp312-cp312-manylinux_2_39_riscv64.whl" + "hash": "1b5ed9162c0c098e0bbc2cf88a94f433c1b8926f831745252e099e5d83e17759", + "url": "https://files.pythonhosted.org/packages/63/2c/eb487fafc9f50ffff2b1e0b697f70fb34bf150821c08ab225aacf5583a7e/greenlet-3.5.5-cp312-cp312-manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "7faba15ac005376e02a0384504e0243be3370ce010296a44a820feb342b505ab", - "url": "https://files.pythonhosted.org/packages/9f/57/079cfe76bcef36b153b25607ee91c6fcb58f17f8b23c86bbbeabe0c88d72/greenlet-3.5.3-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl" + "hash": "3134291427bb0f3526e9d90311988caf336eb43730e95244997a4fb15f45144f", + "url": "https://files.pythonhosted.org/packages/70/12/f7df98e72a8eb4a7edfec5a08d6d1a4ab53a52c95ba0b2ea6c10b8dd9bd0/greenlet-3.5.5-cp311-cp311-manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "e18619ba655ac05d78d80fc83cac4ba892bd6927b99e3b8237aee861aaacc8bb", - "url": "https://files.pythonhosted.org/packages/b0/a0/68afd1ebad40db87dac0a28ffa120726b98bf9c7c40c481b0f63c105d298/greenlet-3.5.3-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl" + "hash": "86c5113d698cb8d927b2750bb1f1d59eefe3a37e0e0217491aee29a7f84ef52c", + "url": "https://files.pythonhosted.org/packages/74/3f/b31e6bd6adb8f80492efb6a47e8f9cd0e7335db5aac2795b1876d5afcfee/greenlet-3.5.5-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl" }, { "algorithm": "sha256", - "hash": "0f71be4920368fe1fabeeaa53d1e3548337e2b223d9565f8ad5e392a75ba23fc", - "url": "https://files.pythonhosted.org/packages/b4/bf/1c65e9b94a54d547068fa5b5a8a06f221f3316b48908e08668d29c77cb50/greenlet-3.5.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl" + "hash": "147b25a42e5ca5be3d42356e8f608b37af715a1c196e9bf9d1627f3341adfe1d", + "url": "https://files.pythonhosted.org/packages/78/ac/5c5b959999b6f09c3026b5dfe171575bc3121c5236ce74f495096f25b203/greenlet-3.5.5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "4d77e67f65f98449e3fb83f795b5d0a8437aead2f874ca89c96576caf4be3af6", - "url": "https://files.pythonhosted.org/packages/b8/c7/b66baacc95775ad511287acb0137b95574a9ce5491902372b7564799d790/greenlet-3.5.3-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl" + "hash": "6ca5d6ae0739e5764f2cfcfaa562ac5a990cbdaedca93251c5e3cf07c362371f", + "url": "https://files.pythonhosted.org/packages/9b/30/87c212b5c684d0e72974f1063b7a9687631e8985902c06e1016542c874e7/greenlet-3.5.5-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl" }, { "algorithm": "sha256", - "hash": "1dae6e0091eae084317e411f047f0b7cb241c6db570f7c45fd6b900a274914ce", - "url": "https://files.pythonhosted.org/packages/b9/42/ba41c97ec36aa4b3ec25e5aa691d79561254805fad7f2f826dd6770587e2/greenlet-3.5.3-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl" + "hash": "19d59f068887d8c5907fc177f27683413ace3011b6ed646c0b309266e74a6502", + "url": "https://files.pythonhosted.org/packages/9c/dc/17d3a5acceb2fd0bbc9682a228117b719cdfb68085e6dbb33fa325755f27/greenlet-3.5.5-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "73f152c895e09907e0dbe24f6c2db37beb085cd63db91c3825a0fcd0064124a8", - "url": "https://files.pythonhosted.org/packages/cc/a8/b85525a6c8fba9f009a5f7c8df1545de8fb0f0bf3e0179194ef4e500317f/greenlet-3.5.3-cp310-cp310-musllinux_1_2_aarch64.whl" + "hash": "655bca754a2ef4efcb0eb48a94d3f4593536d0f3d48f8ed44343c01d16a92f95", + "url": "https://files.pythonhosted.org/packages/a4/17/cd5134be659cd4a443e7a61ae670dabec165a814c51162916d637b6dd38e/greenlet-3.5.5-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "5121af01cf911e70056c00d4b46d5e9b5d1415550038573d744138bacb59e6b8", - "url": "https://files.pythonhosted.org/packages/d8/33/6c87ab7ba663f70ca21f3022aad1ffe56d3f3e0521e836c2415e13abcc3c/greenlet-3.5.3-cp311-cp311-musllinux_1_2_x86_64.whl" + "hash": "03551ed792cb1b4fc0277a0c60dfd8c343894a0ba06fe60dcd22f568b433da39", + "url": "https://files.pythonhosted.org/packages/ac/58/ed98b80ac5738c149a5258544843c45601ade1fd70f61740cdaead6351b3/greenlet-3.5.5-cp311-cp311-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "a61efc018fd3eb317eeca31aba90ee9e7f26f22884a79b6c6ec715bf71bb62f1", - "url": "https://files.pythonhosted.org/packages/e2/f1/fbbfef6af0bad0548f09bc28948ea3c275b4edb19e17fc5ca9900a6a634d/greenlet-3.5.3.tar.gz" + "hash": "27493374cff1d1b7919dc8126547f2aea582737e3046147b434b1e12de56389b", + "url": "https://files.pythonhosted.org/packages/c8/8b/6acf112ed8aee499f25b4d6949820fb02ac950ff9c1f3d793bd5be0599f2/greenlet-3.5.5-cp312-cp312-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "c180d22d325fb613956b443c3c6f4406eb70e6defc70d3974da2a7b59e06f48c", - "url": "https://files.pythonhosted.org/packages/f5/a1/1f7f0c555f5858fd2906fe9f7b0a3554fddb85cb70df7a6aaec41dc292c2/greenlet-3.5.3-cp310-cp310-macosx_11_0_universal2.whl" + "hash": "35cbb8bf55ace57fbccb4fb8622c4521713acd8691e77f4696d416ea7ca527da", + "url": "https://files.pythonhosted.org/packages/d8/c0/b27589e25d220289edcd4d582b2b17b83058d1a56d53d971b6ea1a34f10d/greenlet-3.5.5-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "9bcd2d72ccd70a1ec68ba6ef93e7fbb4420ef9997dabc7010d893bd4015e0bec", - "url": "https://files.pythonhosted.org/packages/f5/c7/28747042e1df8a9cd120a1ebe15529fc4be3b486e13e8d551ff307a82412/greenlet-3.5.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl" + "hash": "8a268024ce2d7d2b04694bf1594058981a9fa663d1df4b762dee499211ed7c1c", + "url": "https://files.pythonhosted.org/packages/db/51/6f732f9314cda54c5fd48a7620c7160f4f286967e8045ad94b9d66ce80b7/greenlet-3.5.5-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "5795cd1101371140551c645f2d408b8d3c01a5a29cf8a9bce6e759c983682d23", - "url": "https://files.pythonhosted.org/packages/fb/fb/d97dc261209c80744b7c8132693a30d70ec6e7315e632cb0a10b3fec94dd/greenlet-3.5.3-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl" + "hash": "f1e2db190db51c17433eee424803818cf0670bf049d9cfe0dd07be111d1aa7c4", + "url": "https://files.pythonhosted.org/packages/f6/ff/c3855a00c2417e8f61c7b9f0bc4f8f599c6928f5c15681ad251e78a91e05/greenlet-3.5.5-cp310-cp310-musllinux_1_2_x86_64.whl" } ], "project_name": "greenlet", @@ -1883,7 +2103,7 @@ "setuptools; extra == \"test\"" ], "requires_python": ">=3.10", - "version": "3.5.3" + "version": "3.5.5" }, { "artifacts": [ @@ -1962,35 +2182,38 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", - "url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl" + "hash": "815e7be7a7806d54abb586dc943addc79e8b2ee16915059658cbeff4b1b43bf4", + "url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", - "url": "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz" + "hash": "5e0811a4383b21dc5838069f801c4fb62113b7447663d2530d2bd6e77b49bf15", + "url": "https://files.pythonhosted.org/packages/5f/f7/abb373e5757eaec4b922b92f97ec8d6d7e057cf06778247604fbc4e7c3f3/idna-3.19.tar.gz" } ], "project_name": "idna", "requires_dists": [ + "coverage>=7.10.0; extra == \"all\"", + "hypothesis>=6.141.1; extra == \"all\"", "mypy>=1.11.2; extra == \"all\"", "pytest>=8.3.2; extra == \"all\"", - "ruff>=0.6.2; extra == \"all\"" + "ruff>=0.16.0; extra == \"all\"", + "ty>=0.0.37; extra == \"all\"" ], "requires_python": ">=3.9", - "version": "3.18" + "version": "3.19" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", - "url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl" + "hash": "bba5600596a7e21f3eef53281cf28d6a5195634d2f2b78ff9501a3272c6eaab0", + "url": "https://files.pythonhosted.org/packages/b3/55/ecca97ae19075f1fac62def77731e7f535e6c1fb8f92ff08160c5e6dade8/importlib_metadata-9.0.1-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", - "url": "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz" + "hash": "ab830580bc0ef3db61ce8fae716389e5462b67e033018bab6d8f80ef17172f99", + "url": "https://files.pythonhosted.org/packages/6f/7e/1e7e8dc30634b93ebb3d58a3dea569ad146e656218d3960ab04f62047b29/importlib_metadata-9.0.1.tar.gz" } ], "project_name": "importlib-metadata", @@ -2006,7 +2229,7 @@ "pytest-cov; extra == \"cover\"", "pytest-enabler>=3.4; extra == \"enabler\"", "pytest-mypy>=1.0.1; platform_python_implementation != \"PyPy\" and extra == \"type\"", - "pytest-perf>=0.9.2; extra == \"test\"", + "pytest-perf>=0.17; extra == \"test\"", "pytest-ruff>=0.2.1; sys_platform != \"cygwin\" and extra == \"check\"", "rst.linker>=1.9; extra == \"doc\"", "sphinx-lint; extra == \"doc\"", @@ -2014,7 +2237,7 @@ "zipp>=3.20" ], "requires_python": ">=3.10", - "version": "9.0.0" + "version": "9.0.1" }, { "artifacts": [ @@ -2653,134 +2876,134 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "f02cf17a6ca1abe29b5f980644f7551f94d71f2011509b26d8625ce038f0df64", - "url": "https://files.pythonhosted.org/packages/17/dd/fa8bd265110dfa51c20cb529f9e6d240a16fafe7e645004c6af2d01353ba/msgpack-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl" + "hash": "4b554d8164ebb526892194f71dcd96ef1fefe0c250087498785d3ffc04a80be3", + "url": "https://files.pythonhosted.org/packages/be/af/91b0d8d3fb3063e259daee3ea8515cea6282f68f4b0e5f0b6fea25762c6e/msgpack-1.2.2-cp312-cp312-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "a28d076ca7c82b9c8728ad90b7147489449557038bed50e4241eb832395169b4", - "url": "https://files.pythonhosted.org/packages/03/8d/671d81534ea0e2b0e8a121be100020da09eb78861fe3aa8f3ef7dcd3bed1/msgpack-1.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + "hash": "a9b4cf3685a135666d27d0d7a73fece74e2fad01d9b508fded89e843512f0e90", + "url": "https://files.pythonhosted.org/packages/03/f7/a6bf145f7d3eb734b3d97fa295f8007a586799ef56b456c8b27bff62caac/msgpack-1.2.2-cp310-cp310-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "67f6dd22fa72a93752643f07889796d62739a13415ee630169a8ce764f86cf9f", - "url": "https://files.pythonhosted.org/packages/09/11/f8563e471093420cf6478cb3271a0175d8402b82d879783d4035d2d03360/msgpack-1.2.1-cp311-cp311-musllinux_1_2_x86_64.whl" + "hash": "46ec851571d8f1b6e29794ebb9dd36f785008da6d14f57c702e60781d6caf648", + "url": "https://files.pythonhosted.org/packages/0e/03/c1e0035e1f923f548b7016a2fef5afea431cdae95d397c5aa52ed75dde05/msgpack-1.2.2-cp310-cp310-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "aded5bdf32609dc7987a49bbbd15a8ef096193f96dd8bbeb791de729e650acf5", - "url": "https://files.pythonhosted.org/packages/0c/3a/dd518a1bf78ed1e9ad8afe57307c079a00eafe4b3068932a27ca1ea56b4f/msgpack-1.2.1-cp311-cp311-macosx_11_0_arm64.whl" + "hash": "7fe374ba76eb0ecca13a1703daa8fa85825a6ddddbb52d4c1a732fa524194683", + "url": "https://files.pythonhosted.org/packages/0f/df/e20bcf5c149890545334743b212eb4b82e1a25fe0a34f99753a1755bfab5/msgpack-1.2.2-cp311-cp311-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "1dabedcd0f23559f3596428c6589c1cd8c6eaed3a0d720795b07b0225d769203", - "url": "https://files.pythonhosted.org/packages/19/9f/a70c9cb1a04ecc134005149367dcfe35d167284e8f65035a1e4156ad17b5/msgpack-1.2.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "86f173a584f72f6164801f31866d22a581f60c991572cf922aed9ab8eb422b77", + "url": "https://files.pythonhosted.org/packages/17/92/d91a08a913a3bbafbede5b9dbf48e4e517f7d92510877b6b02730060ea85/msgpack-1.2.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "60926b75d00c8e816ef98f3034f484a8bc64242d66839cef4cf7e503142316a0", - "url": "https://files.pythonhosted.org/packages/26/aa/753ad8b007b464e1d8aa0c8e650b9c5f4f725e658fc5ac8a7635c55b7f6e/msgpack-1.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "42fd9260416885b4815caca5bdd14dfd5dda6cdade732d6c09104ef8f6228761", + "url": "https://files.pythonhosted.org/packages/2a/fd/d8533fed473cc3e309a701e851d0e5fe36ada5552a3899025f5c69fbe877/msgpack-1.2.2-cp311-cp311-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "04c721c2c7448767e9e3f2520a475663d8ee0f09c31890f6d2bd70fd636a9647", - "url": "https://files.pythonhosted.org/packages/31/f9/c0a1c127f9049db9155afc316952ea571720dd01833ff5e4d7e8e6352dbb/msgpack-1.2.1.tar.gz" + "hash": "4a4348705be86e029d04e741cf9ed0dfe03e942d7d3b92e838fa80d3aa2c3ebc", + "url": "https://files.pythonhosted.org/packages/31/78/90c15bebb1a72667349ca62d4507e9d9369e7f8f76b95f490b823d3622e5/msgpack-1.2.2-cp312-cp312-macosx_10_13_x86_64.whl" }, { "algorithm": "sha256", - "hash": "350cb813d0af6e65d2f7ef0d729f7ff5be5a8bce03665892f43e5883d4ecc1b8", - "url": "https://files.pythonhosted.org/packages/3d/dc/9ebe654a73c3aed2e40aa6b52e3c2a02b5f53ef0085fa235a45d5b367f87/msgpack-1.2.1-cp310-cp310-musllinux_1_2_aarch64.whl" + "hash": "58ce37a4a54577115922385d37201d9a44d66d0167dfbbf4770a2e9bf8ea7ba3", + "url": "https://files.pythonhosted.org/packages/3f/f5/ae93f85b063d744731cb285528210cd950333b167cacc7b2f96e1420a475/msgpack-1.2.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "ee1d9ed27d0497b848923746cf762ed2e7db24f4be7eec8e5cbe8c766aa707b7", - "url": "https://files.pythonhosted.org/packages/42/eb/b67cf64218a2fa25e1c671fe1d3dbb06cbeb973e71bc4b822da079862d0b/msgpack-1.2.1-cp310-cp310-musllinux_1_2_riscv64.whl" + "hash": "77c2e018417dc1d66f235e383877ee885b60ade9d29e494dd581e08af2cb1923", + "url": "https://files.pythonhosted.org/packages/41/f0/29f591bea185616cf417645ac03bd3ad9b317483ad8572160e325f7fe777/msgpack-1.2.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "d3567748a5107cb40cdf66a275430c2f87c07777698f4bfd25c35f44d533258c", - "url": "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl" + "hash": "9bd3d1557c3fe1a095068210708a03e3e4795973392af6f4047060e70abd9a6c", + "url": "https://files.pythonhosted.org/packages/44/92/541e9fa4623587767623788b38d11fc78d402acb1421962a13d3ace48bef/msgpack-1.2.2-cp310-cp310-musllinux_1_2_riscv64.whl" }, { "algorithm": "sha256", - "hash": "4202c74688ca06591f78cb18988228bd4cca2cc75d57b60008372892d2f1e6e6", - "url": "https://files.pythonhosted.org/packages/5a/cc/85039b7b0eb168aaad7383a23c97e291a11f08351cb45a606ce865e4e3f1/msgpack-1.2.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "0e91332144f69bc3018c91232fac26da580ef748fb8eaddd7914d4458001cc4f", + "url": "https://files.pythonhosted.org/packages/4e/8e/c70c8c9180c5ddf4440eb8658ebead98e22e7686fbf84f6b165031430750/msgpack-1.2.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "8c7b398c56ff125feae96c2737abfec5595f1fa0aa186df60c56040b8accb95c", - "url": "https://files.pythonhosted.org/packages/5b/16/f70100614b69feb3ade7285f08c9c52d6cda0a5c03f3f5e2facd63acb211/msgpack-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl" + "hash": "3e915d390d7068b257ca8b62f3fc59fad135c8631d1017ab03b0b924b07c5367", + "url": "https://files.pythonhosted.org/packages/50/9a/f10ce11fa62700c9ab87a22e65b9ca272f7f673ddd31aeb2de6ae272ad35/msgpack-1.2.2-cp312-cp312-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "020e881a764b20d8d7ca1a54fc01b8175519d108e3c3f194fddc200bda95951a", - "url": "https://files.pythonhosted.org/packages/6a/fd/6adabd4f6d5e686f97dd02ce7fce3fe4cf672cbac36b8f67ff4040e8ad8b/msgpack-1.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + "hash": "9d7fb25b4442fae0cb2590272d06ab4f6caa526ee36a994edb81e946b874813e", + "url": "https://files.pythonhosted.org/packages/53/fd/a05ba8f84c5951c9aec2a19c1c81f6c4a67b8bec80af604ac5b23ccfa019/msgpack-1.2.2-cp311-cp311-macosx_10_9_x86_64.whl" }, { "algorithm": "sha256", - "hash": "146ee4e9ce80b365c6d4c47073da9da7bcec473e58194ceee5dd7620ace77e06", - "url": "https://files.pythonhosted.org/packages/70/e0/7ba9e1542bf0771a27b8b37c1316e3f95ae9d748fd765284655c476ad4ef/msgpack-1.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "9eb0b0e602064527a045ea28c4f174ed69383587e29cebe28947e3b84106eb2a", + "url": "https://files.pythonhosted.org/packages/6d/44/ea2100ec54d30c46ee9dba10a3bfb79b655e96c6df237238a3234c75869b/msgpack-1.2.2.tar.gz" }, { "algorithm": "sha256", - "hash": "779197a6513bab3c3632265e3d0f7cb3227e62510841a6f34f1eaa37efbb345e", - "url": "https://files.pythonhosted.org/packages/70/ff/59aa3887b860bbf43532835e192b1c388a17590d6068ae4f8b2bc74c906e/msgpack-1.2.1-cp311-cp311-musllinux_1_2_riscv64.whl" + "hash": "c522420d78db2431887d45b518e304d86e27b9ad0b30f24e3806a6ad5d8bdbfc", + "url": "https://files.pythonhosted.org/packages/82/fe/d7be978456ff8552e69a8e270d882e7530e01513c096b293d83df03753ea/msgpack-1.2.2-cp312-cp312-musllinux_1_2_riscv64.whl" }, { "algorithm": "sha256", - "hash": "01e2dd6c9b19d333a00282330cc8a73d38d8dabc306dc5b42cd668c3ac82e833", - "url": "https://files.pythonhosted.org/packages/79/70/fb7668ce0386819303047057aef6fc1da73b584291d9cff82b821744e2ef/msgpack-1.2.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "0a652ceeededf71d3fa40c303a02a149d42338d310162367b91c539d4bd6e0a3", + "url": "https://files.pythonhosted.org/packages/88/88/c2b6d8e81571da87aa232c0e34a3f3a0e618e6235892065ec82d1d81fc7a/msgpack-1.2.2-cp312-cp312-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "633727297ed063441fd1cda2288865487f33ad14eeb8831afb5f0c396a62cfce", - "url": "https://files.pythonhosted.org/packages/a2/2e/9ee200cde32fd1a0101b4006202fde554c1860adfb9bf7bff31ea4c08df8/msgpack-1.2.1-cp310-cp310-musllinux_1_2_x86_64.whl" + "hash": "f11e09f10210a91c169e39c7a5a1f9090eaa73ad75555fafad5023c3053c47ba", + "url": "https://files.pythonhosted.org/packages/93/15/17374efe9793f5332c7d4727ab40539f95a1dc9df653531795daca8c4281/msgpack-1.2.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "e4f1d0f8f98ade9634e01fb704a408f9336c0a8f1117b369f5db83dc7551d8b1", - "url": "https://files.pythonhosted.org/packages/a6/df/8e2ac970c8f99264cd9997d1c73df5466bc19da3301d7dc5500862a9b089/msgpack-1.2.1-cp312-cp312-musllinux_1_2_riscv64.whl" + "hash": "4710d881d8fb047deed2485707409116722af2b992d3fefd73c7667c4e350839", + "url": "https://files.pythonhosted.org/packages/93/1a/77d32a60a80ee67016e77b13bec07e85f1929a92f046da044591c7eb01c9/msgpack-1.2.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "8ff92d7feeaf5bc26c51495b69e2f99ed97ab79346fb6555f44be7dd2ac6503b", - "url": "https://files.pythonhosted.org/packages/a8/46/62ed8c2e87d7021eab19921594d961ef3aa3794eec76c716dc30f3bfd433/msgpack-1.2.1-cp311-cp311-musllinux_1_2_aarch64.whl" + "hash": "b9b0c1f2aa7b0026b4bd50718100e8b04175e4f36e160aa852502377b5e572e7", + "url": "https://files.pythonhosted.org/packages/ac/c3/00dcd902d66a641b9ba350783feb482ea5c1ca4a7ff6629db0c10c0ea982/msgpack-1.2.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "2ef59c659f289eddf8aa6623823f19fa2f40a4029266889eac7a2505dd210c35", - "url": "https://files.pythonhosted.org/packages/bc/dd/9e8cbd8f5582ca4b590336f2b91ee5662f6a6ca562b565abaf696a0f81ff/msgpack-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl" + "hash": "e05a94a0442de86818a30281c6cc2cb9cc7aa148386fd3541c4d4774b73cb3a9", + "url": "https://files.pythonhosted.org/packages/b5/a4/27400c101a96115fe8484cad57b6c5eb4f9ffba080a1d9be62ec9174bf67/msgpack-1.2.2-cp310-cp310-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "7d31c0ac0c640f877804c67cb2bc9f4e23dc2db97e96c2e67fa27d38283b41f8", - "url": "https://files.pythonhosted.org/packages/d2/b6/e5c737515ed1f166664b87601b532f58cbb73d8aa6a90b99f7c2c5037e8e/msgpack-1.2.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "7afa5431f6f3487c584187ca6c8e2a34e9b106529893b3e720eabb068f6ac970", + "url": "https://files.pythonhosted.org/packages/c9/40/181c8944b28f779ed0b2587d24cc0ccf1bc87248204105327140aa20d63d/msgpack-1.2.2-cp310-cp310-macosx_10_9_x86_64.whl" }, { "algorithm": "sha256", - "hash": "1548006a91aa93c5da81f3bdcebc1a0d10cea2d25969754fbe848da622b2b895", - "url": "https://files.pythonhosted.org/packages/e4/3c/08ecd5cdfe4e2de43aec79062028ad0f7b2d9b1fea5430068c198ba570da/msgpack-1.2.1-cp310-cp310-macosx_11_0_arm64.whl" + "hash": "8b1415d02e9bf722672af8a90f90813265a0cd0b14163187261e54a5592bc949", + "url": "https://files.pythonhosted.org/packages/d3/af/2b567d684f912fedcefe3f7c37de604716ffa99336bd432688f9f040df92/msgpack-1.2.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "8b267ce94efb76fbd1b3373511420074ee3187f0f7811bf394531de13294735a", - "url": "https://files.pythonhosted.org/packages/ed/bf/35963899493b32030c85fc513b723ae66144ac70c11ebc52e889e16e3d99/msgpack-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl" + "hash": "336525cc2688e43ea77dfb1a4ce012c8cde561835913801dbfcfdcf4111d8abb", + "url": "https://files.pythonhosted.org/packages/d6/1b/57906337bfee0ead554571dc203ea17c3fad26d51e5eca6271ecd983f73b/msgpack-1.2.2-cp311-cp311-musllinux_1_2_riscv64.whl" }, { "algorithm": "sha256", - "hash": "29a3f6e9667868429d8240dfd063ea5ffdc1321c13d783aa23827a38de0dcb22", - "url": "https://files.pythonhosted.org/packages/f4/6b/e9b1cdc042c4458801d2545ed782a95f3d6ba8e270cce8745b8603c7f748/msgpack-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl" + "hash": "90986cc9aab9d7d1d8f38bcbf65d3f7ac83bdd90c35765db7d691b4829698cba", + "url": "https://files.pythonhosted.org/packages/da/c0/d3ede9f5d16acb4c05a9281859f1e99ef9f877a928eb78454c37f70db001/msgpack-1.2.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "83efa1c898e0fc5380fc0cabbf75164c52e3b5cbb45973710d75821928380c73", - "url": "https://files.pythonhosted.org/packages/fa/7f/5ce020168cf0439041526e95aa068c722c016aee21624e331aeabeee2e8e/msgpack-1.2.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + "hash": "cdb6cc6e1127d15879c47a8b3270716243da82d3e7feab1f5946872c75b3d60f", + "url": "https://files.pythonhosted.org/packages/de/0f/5d1e6d68e516621697a9262b24917d678793e838cf3f331ed4656b3e959d/msgpack-1.2.2-cp311-cp311-musllinux_1_2_x86_64.whl" } ], "project_name": "msgpack", "requires_dists": [], "requires_python": ">=3.10", - "version": "1.2.1" + "version": "1.2.2" }, { "artifacts": [ @@ -2897,195 +3120,135 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "71e63adb0e1f1ed5d9e168f50a91ceb93ae6420731d222dc7da5c69409aa47aa", - "url": "https://files.pythonhosted.org/packages/df/e5/4d2d8af06f788329b4f78f8cc3679bb395392fcaa1e4d8d3c33e85308fa4/orjson-3.11.9-cp312-cp312-musllinux_1_2_x86_64.whl" - }, - { - "algorithm": "sha256", - "hash": "03db380e3780fa0015ed776a90f20e8e20bb11dde13b216ce19e5718e3dfba62", - "url": "https://files.pythonhosted.org/packages/05/94/b0d27090ea8a2095db3c2bd1b1c96f96f19bbb494d7fef33130e846e613d/orjson-3.11.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" - }, - { - "algorithm": "sha256", - "hash": "87e4d4ab280b0c87424d47695bec2182caf8cfc17879ea78dab76680194abc13", - "url": "https://files.pythonhosted.org/packages/09/d3/c5824260ca8b9d7ba82648d042a3f8f4815d18c15bb98a1f30edd1bb2d83/orjson-3.11.9-cp310-cp310-musllinux_1_2_armv7l.whl" - }, - { - "algorithm": "sha256", - "hash": "33d7d766701847dc6729846362dc27895d2f2d2251264f9d10e7cb9878194877", - "url": "https://files.pythonhosted.org/packages/09/eb/75d50c29c05b8054013e221e598820a365c8e64065312e75e202ed880709/orjson-3.11.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl" - }, - { - "algorithm": "sha256", - "hash": "0b34789fa0da61cf7bef0546b09c738fb195331e017e477096d129e9105ab03d", - "url": "https://files.pythonhosted.org/packages/0b/ee/66154baf69f71c7164a268a5e888908aec5a0819d13c81d5e2755a257758/orjson-3.11.9-cp310-cp310-musllinux_1_2_aarch64.whl" - }, - { - "algorithm": "sha256", - "hash": "3513550321f8c8c811a7c3297b8a630e82dc08e4c10216d07703c997776236cd", - "url": "https://files.pythonhosted.org/packages/0e/30/3178eb16f3221aeef068b6f1f1ebe05f656ea5c6dffe9f6c917329fe17a3/orjson-3.11.9-cp311-cp311-musllinux_1_2_aarch64.whl" - }, - { - "algorithm": "sha256", - "hash": "be4fa4f0af7fa18951f7ab3fc2148e223af211bf03f59e1c6034ec3f97f21d61", - "url": "https://files.pythonhosted.org/packages/0e/a4/82b7a2fe5d8a67a59ed831b24d59a3d46ea7d207b66e1602d376541d94a6/orjson-3.11.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" - }, - { - "algorithm": "sha256", - "hash": "135869ef917b8704ea0a94e01620e0c05021c15c52036e4663baffe75e72f8ce", - "url": "https://files.pythonhosted.org/packages/10/5d/b95ca542a001135cc250a49370f282f578c8f4e46cc8617d73775297eea8/orjson-3.11.9-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl" - }, - { - "algorithm": "sha256", - "hash": "231742b4a11dad8d5380a435962c57e91b7c37b79be858f4ef1c0df1a259897e", - "url": "https://files.pythonhosted.org/packages/16/64/bd815f5c610b3facc204f26ba94e87a9eb49b0d83de3d5fc1eee2402d91b/orjson-3.11.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" - }, - { - "algorithm": "sha256", - "hash": "9ef6fe90aadef185c7b128859f40beb24720b4ecea95379fc9000931179c3a49", - "url": "https://files.pythonhosted.org/packages/16/6d/11867a3ffa3a3608d84a4de51ef4dd0896d6b5cc9132fbe1daf593e677bc/orjson-3.11.9-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl" - }, - { - "algorithm": "sha256", - "hash": "3ebca4179031ee716ed076ffadc29428e900512f6fccee8614c9983157fcf19c", - "url": "https://files.pythonhosted.org/packages/16/fa/9d54b07cb3f3b0bfd57841478e42d7a0ece4a9f49f9907eecf5a45461687/orjson-3.11.9-cp311-cp311-macosx_15_0_arm64.whl" - }, - { - "algorithm": "sha256", - "hash": "f01c4818b3fc9b0da8e096722a84318071eaa118df35f6ed2344da0e73a5444f", - "url": "https://files.pythonhosted.org/packages/1e/51/3fb9e65ae76ee97bd611869a503fa3fc0a6e81dd8b737cf3003f682df7ff/orjson-3.11.9-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl" + "hash": "532ff8cd4bd59a327a953a7dcde922c7fc25b85e29721bb8633265430d3a3873", + "url": "https://files.pythonhosted.org/packages/71/93/4d71f2df314a97ff0d27a4559bf5888fc8406e3c6dec90e92291e3511215/orjson-3.12.0-cp312-cp312-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "53b50b0e14084b8f7e29c5ce84c5af0f1160169b30d8a6914231d97d2fe297d4", - "url": "https://files.pythonhosted.org/packages/1f/7d/30e844b3dac3f74aed66b1f984daf9db3c98c0328c03d965a9e8dc06449e/orjson-3.11.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl" + "hash": "a791f793b287bbc135b8e87c34e35c8bfc693e2a8a620fab1ae682b925f9a32e", + "url": "https://files.pythonhosted.org/packages/04/d1/3b2038ed168d22e14182ed715d6963f9c073a83a2ba43cfe918a4fc43c64/orjson-3.12.0-cp311-cp311-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "e5c9b8f28e726e97d97696c826bc7bea5d71cecd63576dba92924a32c1961291", - "url": "https://files.pythonhosted.org/packages/24/75/05912954c8b288f34fcf5cd4b9b071cb4f6e77b9961e175e56ebb258089f/orjson-3.11.9-cp312-cp312-macosx_15_0_arm64.whl" + "hash": "a696529ec96a90d9a5f9570207efe403c8b08f8e4aa2783ee3403511e2fdfa10", + "url": "https://files.pythonhosted.org/packages/05/34/c2eb3b2900e5597db7841a4c6416ac2d90081bd956b02d4dd1833fa2b96b/orjson-3.12.0-cp311-cp311-macosx_15_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "71f3db16e69b667b132e0f305a833d5497da302d801508cbb051ed9a9819da47", - "url": "https://files.pythonhosted.org/packages/2a/56/d54152b67b63a0b3e556cfc549d6ce84f74d7f425ddeadc6c8a74d913da7/orjson-3.11.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + "hash": "d14203fb1aae2ad9b3d52f8a0e82aeb10197ef1c9bc61da7f358bd70b00123d5", + "url": "https://files.pythonhosted.org/packages/0f/f3/742fb1f62b825f2c010697eaf4e828004bc2a81e7e806666989c132c7c42/orjson-3.12.0.tar.gz" }, { "algorithm": "sha256", - "hash": "c2d3dc759490128c5c1711a53eeaa8ee1d437fd0038ffd2b6008abf46db3f882", - "url": "https://files.pythonhosted.org/packages/31/6a/6cf69385a58208024fcb8c014e2141b8ce838aba6492b589f8acfff97fab/orjson-3.11.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl" + "hash": "18a87929f31d94a77f7dc93cf527e91f39ce7fe7813d588a4de2507efd32a387", + "url": "https://files.pythonhosted.org/packages/14/6d/e3a8c34d687895aecd8b267a01c46106eb98d8424a83bfa7bacb723854f6/orjson-3.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" }, { "algorithm": "sha256", - "hash": "cde1a448023ba7d5bb4c01c5afb48894380b5e4956e0627266526587ef4e535f", - "url": "https://files.pythonhosted.org/packages/3a/dc/7446c538590d55f455647e5f3c61fc33f7108714e7afcffa6a2a033f8350/orjson-3.11.9-cp312-cp312-musllinux_1_2_i686.whl" + "hash": "bc7a872f03522d90e0429e6c0c5cd23084f767bedcb4c58048eec19294613344", + "url": "https://files.pythonhosted.org/packages/15/12/644cbbcabb26df61d9ef0c66e6f2bf8b687cc7b66137597f2858951f1952/orjson-3.12.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl" }, { "algorithm": "sha256", - "hash": "147302878da387104b66bb4a8b0227d1d487e976ce41a8501916161072ed87b1", - "url": "https://files.pythonhosted.org/packages/49/bd/360686f39348aa88827cb6fbf7dc606fd41c831a35235e1abf1db8e3a9e6/orjson-3.11.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + "hash": "e4ac5059baab4b3acbd99485de019ff8cda0fdf34b61fa74f7197a53db78bfe8", + "url": "https://files.pythonhosted.org/packages/1c/df/b49081766a75b6a37b3d33bdc0a39e492abab8441dd25e3e1998e7b83fcb/orjson-3.12.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.whl" }, { "algorithm": "sha256", - "hash": "4da3c38a2083ca4aaf9c2a36776cce3e9328e6647b10d118948f3cfb4913ffe4", - "url": "https://files.pythonhosted.org/packages/4e/61/73d49333bba660a075daccca10970dc6409ce1cf42ae4046646a19468aad/orjson-3.11.9-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl" + "hash": "11edb4660a6680abee9788a3a9072208a2c96538cc1322bd79542065229d8e54", + "url": "https://files.pythonhosted.org/packages/29/98/758cf90fbeaaafb7f8141bfac75a432099959f3a2f5db93a412e876415d8/orjson-3.12.0-cp312-cp312-macosx_15_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "a8f5f8bc7ce7d59f08d9f99fa510c06496164a24cb5f3d34537dbd9ca30132e2", - "url": "https://files.pythonhosted.org/packages/50/c7/375e83a76851b73b2e39f3bcf0e5a19e2b89bad13e5bca97d0b293d27f24/orjson-3.11.9-cp312-cp312-musllinux_1_2_aarch64.whl" + "hash": "2d3a9da945a4d96ae758fdaaca56742e6b73b6fd554c5d8876f252a6dad70b83", + "url": "https://files.pythonhosted.org/packages/32/b5/5b934d251f8651f7e41df180ad0c57a6e1cabe15c7bd331638413a50ebc9/orjson-3.12.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.whl" }, { "algorithm": "sha256", - "hash": "c5d001196b89fa9cf0a4ab79766cd835b991a166e4b621ba95089edc50c429ff", - "url": "https://files.pythonhosted.org/packages/5f/f1/ff2f19ed0225f9680fafa42febca3570dd59444ebf190980738d376214c2/orjson-3.11.9-cp311-cp311-musllinux_1_2_armv7l.whl" + "hash": "8e29957429c35bbb5a185a119c523aa2428b7bbf1a293724c7b9375ed8f892a3", + "url": "https://files.pythonhosted.org/packages/48/d4/58ea28eeef95c2a27358ed927380a621162cf20bd740bbccf9c3f09a200a/orjson-3.12.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl" }, { "algorithm": "sha256", - "hash": "ace6c58523302d3b97b6ac5c38a5298a54b473762b6be82726b4265c41029f92", - "url": "https://files.pythonhosted.org/packages/64/cb/509c2e816fe4df641d93dc92f6a89adc8df3ada8ebdee2bd44aba3264c3c/orjson-3.11.9-cp310-cp310-musllinux_1_2_i686.whl" + "hash": "103b5db66aa53c1f9e88c2524be4f383e831ba7dfd5f9f5af6336a177c622f11", + "url": "https://files.pythonhosted.org/packages/4c/a6/22e863bbbe8917aa292e33e0db597000f9a07eb5e6f52efed623fa16bae1/orjson-3.12.0-cp310-cp310-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "4fef17e1f8722c11587a6ef18e35902450221da0028e65dbaaa543619e68e48f", - "url": "https://files.pythonhosted.org/packages/7e/0c/964746fcafbd16f8ff53219ad9f6b412b34f345c75f384ad434ceaadb538/orjson-3.11.9.tar.gz" + "hash": "bf44e374aadde77b1f6109f1030be51433eb61984379852766b6f4e187db7b1e", + "url": "https://files.pythonhosted.org/packages/50/22/0644b87c73f13e0092df8f35a1fe280d991e5e90072087411e0dd7e44e0c/orjson-3.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" }, { "algorithm": "sha256", - "hash": "4d7fde5501b944f83b3e665e1b31343ff6e154b15560a16b7130ea1e594a4206", - "url": "https://files.pythonhosted.org/packages/7f/7c/49d5d82a3d3097f641f094f552131f1e2723b0b8cb0fa2874ab65ecfffa6/orjson-3.11.9-cp312-cp312-musllinux_1_2_armv7l.whl" + "hash": "bd57d79aefa3f84eec851d6de7a366795b9345cfaf17f82b4820430a7a5fa241", + "url": "https://files.pythonhosted.org/packages/50/a0/ceb5008914a65e9a19a46a09d94bc67a74d120209fdfa772750023ceb377/orjson-3.12.0-cp310-cp310-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "115ab5f5f4a0f203cc2a5f0fb09aee503a3f771aa08392949ab5ca230c4fbdbd", - "url": "https://files.pythonhosted.org/packages/80/01/be33fbff646e22f93398429ea645f20d2097aea1a6cdc1e6628e70125f83/orjson-3.11.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + "hash": "7c2ad193c8004254f34b499f3bd2c80f043d10754aff2b38f93da574f4883f98", + "url": "https://files.pythonhosted.org/packages/58/ab/d9221d4a2b085b073fcddc91728d490f20b9cf010c62c2f42371ab997695/orjson-3.12.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.whl" }, { "algorithm": "sha256", - "hash": "48ee05097750de0ff69ed5b7bbcf0732182fd57a24043dcc2a1da780a5ead3a5", - "url": "https://files.pythonhosted.org/packages/88/b1/6ceafc2eefd0a553e3be77ce6c49d107e772485d9568629376171c50e634/orjson-3.11.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + "hash": "9caf3d09f47c3c70c4451ada20ef9bc4a4cdffa26f49862cf0a253b329aae2d5", + "url": "https://files.pythonhosted.org/packages/5b/e1/15169e9d22b59a406264f99d6db387c0b0b12b6357a8a0169917c2a713eb/orjson-3.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" }, { "algorithm": "sha256", - "hash": "16969c9d369c98eb084889c6e4d2d39b77c7eb38ceccf8da2a9fff62ae908980", - "url": "https://files.pythonhosted.org/packages/9b/61/863bddf0da6e9e586765414debd54b4e58db05f560902b6d00658cb88636/orjson-3.11.9-cp311-cp311-musllinux_1_2_i686.whl" + "hash": "a94f0f0c6fcbb2b5bd9734c57a489c7584a732bbdf04a39e8c83b861e9d03e92", + "url": "https://files.pythonhosted.org/packages/75/1a/a7075a8e8b0d3f5097d17ac3099017104b6b7b42012041147995d5b2da05/orjson-3.12.0-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl" }, { "algorithm": "sha256", - "hash": "277fefe9d76ee17eb14debf399e3533d4d63b5f677a4d3719eb763536af1f4bd", - "url": "https://files.pythonhosted.org/packages/9e/85/0ef63bcf1337f44031ce9b91b1919563f62a37527b3ea4368bb15a22e5d7/orjson-3.11.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl" + "hash": "e9683ee9ea0659da64f36574ef675b8a86330c34c19ea75db1fb93c3ff99e0ef", + "url": "https://files.pythonhosted.org/packages/75/20/930824c07685c22af23f26818ed3853b0270488a412b6ab757904b7f787b/orjson-3.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" }, { "algorithm": "sha256", - "hash": "26a473dbb4162108b27901492546f83c76fdcea3d0eadff00ae7a07e18dcce09", - "url": "https://files.pythonhosted.org/packages/ab/86/1c3a47df3bc8191ea9ac51603bbb872a95167a364320c269f2557911f406/orjson-3.11.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + "hash": "53c0c474a9d9aff9aebfc0c88de1f28f843d940e6e3a80729abdf6a20274356f", + "url": "https://files.pythonhosted.org/packages/80/3d/75c5ac5a69161f44492a68fbdde66f4cc4ce48cd5e1fb05918e46f0c8848/orjson-3.12.0-cp312-cp312-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "63e0efbc991250c0b3143488fa57d95affcabbfc63c99c48d625dd37779aafe2", - "url": "https://files.pythonhosted.org/packages/b6/8a/4081492586d75b073d60c5271a8d0f05a0955cabf1e34c8473f6fcd84235/orjson-3.11.9-cp311-cp311-musllinux_1_2_x86_64.whl" + "hash": "1192a7021b6d071aaf909864f6e924d6a2675ca360485b972b8401749311750b", + "url": "https://files.pythonhosted.org/packages/8c/57/80b986ebfecd9c6a177ddf1c2319717f0cd8feffb2b78946595a18a2fc88/orjson-3.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" }, { "algorithm": "sha256", - "hash": "34fd2317602587321faab75ab76c623a0117e80841a6413654f04e47f339a8fb", - "url": "https://files.pythonhosted.org/packages/c7/35/e744fd36c79b339d27beb06068b5a08a8882ef5418804d0ce545a31f718d/orjson-3.11.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl" + "hash": "b9dca132b1fda5565088e65a6b6e742285e0aeceb6fae549fa8863e16c7d3998", + "url": "https://files.pythonhosted.org/packages/a4/3a/763dbd426290d044ec3e615a05e70adb6d8b6f95bf17dc355c0081a5e8b6/orjson-3.12.0-cp311-cp311-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "011382e2a60fda9d46f1cdee31068cfc52ffe952b587d683ec0463002802a0f4", - "url": "https://files.pythonhosted.org/packages/d7/cf/b33b5f3e695ae7d63feef9d915c37cc3b8f465493dcd4f8e0b4c697a2366/orjson-3.11.9-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl" + "hash": "aa3e43a6846e91d7bde3d5a9c66090fcd8744f569a9b6cffc5e1ca38f6a461c0", + "url": "https://files.pythonhosted.org/packages/be/4a/295da39c651c2faac8bd351a2a346f0fdedd9d50b847ee9dfc27d2207ef6/orjson-3.12.0-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl" }, { "algorithm": "sha256", - "hash": "97d0d932803c1b164fde11cb542a9efcb1e0f63b184537cca65887147906ff48", - "url": "https://files.pythonhosted.org/packages/db/b5/3ceae56d2e4962979eedb023ba6a46a4bb65f333960379be0ca470686220/orjson-3.11.9-cp310-cp310-musllinux_1_2_x86_64.whl" + "hash": "92ffc09e07233a6ab6d4e067f7841edcbcc134cb4812155cf171ea5255a421d7", + "url": "https://files.pythonhosted.org/packages/cd/d2/37efb5b12a176ce3ced29f4144f20da57d02757f78ce549637dc1b4e1fc8/orjson-3.12.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl" }, { "algorithm": "sha256", - "hash": "d8ea516b3726d190e1b4297e6f4e7a8650347ae053868a18163b4dd3641d1fff", - "url": "https://files.pythonhosted.org/packages/e8/f8/0b1bd3e8f2efcdd376af5c8cfd79eaf13f018080c0089c80ebd724e3c7fb/orjson-3.11.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" + "hash": "747843254519dd43b93eee3153a19e5a509334320c4d2f823ec879232db5c796", + "url": "https://files.pythonhosted.org/packages/cf/35/819eeb4fa8ee676d38fdbb8213a76fd496f7dbbfdfafa89d34e02b22dfac/orjson-3.12.0-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl" }, { "algorithm": "sha256", - "hash": "a6082706765a95a6680d812e1daf1c0cfe8adec7831b3ff3b625693f3b461b1c", - "url": "https://files.pythonhosted.org/packages/ea/76/f11311285324a40aab1e3031385c50b635a7cd0734fdaf60c7e89a696f60/orjson-3.11.9-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl" - }, - { - "algorithm": "sha256", - "hash": "380cdce7ba24989af81d0a7013d0aaec5d0e2a21734c0e2681b1bc4f141957fe", - "url": "https://files.pythonhosted.org/packages/f3/59/dab79f61044c529d2c81aecdc589b1f833a1c8dec11ba3b1c2498a02ca7e/orjson-3.11.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl" + "hash": "dce0166feb0a737ab84f598c9a338cbc0b764a036617aa686194f53c7eba0c3e", + "url": "https://files.pythonhosted.org/packages/e2/f4/1e82aa2efc9916422d804697876ce433c907a1abd7c7e5c6d3d48565e5f9/orjson-3.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" } ], "project_name": "orjson", "requires_dists": [], "requires_python": ">=3.10", - "version": "3.11.9" + "version": "3.12.0" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "491767e81c1bb11a54fb68d1a24119bdeede593a2beccca5bc09bfed36fdb35c", + "hash": "b9feb1769b48102061fe4fc59b2f5ad600bc2ac0b55cf12ef5fe49464ac0d230", "url": "git+https://github.com/StackStorm/orquesta.git" } ], @@ -3206,19 +3369,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", - "url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl" + "hash": "d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", + "url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", - "url": "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz" + "hash": "94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", + "url": "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz" } ], "project_name": "packaging", "requires_dists": [], - "requires_python": ">=3.8", - "version": "26.2" + "requires_python": ">=3.9", + "version": "26.3" }, { "artifacts": [ @@ -3292,13 +3455,13 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "2daae7bd422a0fc4f4879fd48c9a1932ed74a0bc7172e1e5f9bde63a101ed074", - "url": "https://files.pythonhosted.org/packages/7f/7b/a09c0d378ee8604220902c58103104b2304ef99744c4b7fc45312d280484/pika-1.4.1-py3-none-any.whl" + "hash": "48de960c97a93b55db06b8be4c53eb977c9c8a2754c57cdae9097abcbd70ce04", + "url": "https://files.pythonhosted.org/packages/7c/f3/921170b78779ac3f8b405cb28fce88acca1562ac114072cbf0a115e19bb9/pika-1.4.4-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "e851f3e4992adfbf8eb64e9b86d94e3382f92ba0200055abedbb29676b8e713b", - "url": "https://files.pythonhosted.org/packages/f7/09/8c42dd00c4b3e09ebd174455d30823c261eefef9d2b7e94ae9ca779704c1/pika-1.4.1.tar.gz" + "hash": "8cfc8b33a5cb16e733bd60cffca9732c0d1d761ecd80a89f34ed7df2cd38d6d6", + "url": "https://files.pythonhosted.org/packages/7f/26/54e0b98a7f60b474cb0a6c05ecf048d4bc8c866e10ab1c82bc83865e7421/pika-1.4.4.tar.gz" } ], "project_name": "pika", @@ -3308,43 +3471,43 @@ "twisted; extra == \"twisted\"" ], "requires_python": ">=3.7", - "version": "1.4.1" + "version": "1.4.4" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "382ff9f685ee3bc25864f820aa50505825f10f5458ffff07e30a6d96e5715cab", - "url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl" + "hash": "71138adf1f4ca900cdb7d289c21b7494329f2332b6d85f0e1c42108c0384ed3e", + "url": "https://files.pythonhosted.org/packages/f3/6e/1736e5b4ae2b778ef2f81c47d797de9f891d4d8acb047a24ca37a60294dd/pip-26.2.1-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "f49cd134c61cf2fd75e0ce2676db03e4054504a5a4986d00f8299ae632dc4605", - "url": "https://files.pythonhosted.org/packages/01/91/47e7d486260f618783899587af63ccf7980fb60245c3e63dd4571c6b57ad/pip-26.1.2.tar.gz" + "hash": "f6ad667e89a1fe78046c8f13232b247200f5258d7828f3f7883d660878e0813f", + "url": "https://files.pythonhosted.org/packages/ae/15/4500e320e6b101ec3b719ae85b697d9940b6cda672bc555bd6016fc60c6f/pip-26.2.1.tar.gz" } ], "project_name": "pip", "requires_dists": [], "requires_python": ">=3.10", - "version": "26.1.2" + "version": "26.2.1" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", - "url": "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl" + "hash": "89f8d42695853b89c7170bd49bc3dc593f98a71e695ede88e06a3b247bc4563b", + "url": "https://files.pythonhosted.org/packages/c7/12/6f3fcd5067a9cbf4f8664b32957973498da8b083455203c8d9cab83a725c/platformdirs-4.11.5-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", - "url": "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz" + "hash": "e8b31f4f8bcbbedef91a6b57a706255e4f148d2a4e01648382a0a47342539173", + "url": "https://files.pythonhosted.org/packages/ea/06/cf1564dcc2e2261c8c8c6c05628dc8b418943bdae2a4e58640ceb2f770fa/platformdirs-4.11.5.tar.gz" } ], "project_name": "platformdirs", "requires_dists": [], "requires_python": ">=3.10", - "version": "4.10.0" + "version": "4.11.5" }, { "artifacts": [ @@ -3410,35 +3573,30 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "d3c362036d625b12aeee495621cb1555fd50b2af3632af3d825176bfb50e073b", - "url": "https://files.pythonhosted.org/packages/a9/a8/fc509e514c708f43102542cdcbc2f42dc49f7a159f90f56d072371629731/prance-25.4.8.0-py3-none-any.whl" + "hash": "b98b26cd968f306e6d4ced3eddb78ef4cceb5311ab3f76d76573fca4a0e01837", + "url": "https://files.pythonhosted.org/packages/05/d3/f966d7fddc2ed0f3c9e196df4f7841020629252915d0eb1f44e47e268b50/prance-26.7.19.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "2f72d2983d0474b6f53fd604eb21690c1ebdb00d79a6331b7ec95fb4f25a1f65", - "url": "https://files.pythonhosted.org/packages/ae/5c/afa384b91354f0dbc194dfbea89bbd3e07dbe47d933a0a2c4fb989fc63af/prance-25.4.8.0.tar.gz" + "hash": "18c52bc9ace4de2b58be1d810543d675a8640f06c2ea5d06427f12f1e612be8d", + "url": "https://files.pythonhosted.org/packages/4a/a8/68f8193e875eb9ab2c4811048e6bdfebf76c33cfdf274e946fd962530f65/prance-26.7.19.0.tar.gz" } ], "project_name": "prance", "requires_dists": [ "PyICU~=2.14; extra == \"icu\"", - "bumpversion>=0.6.0; extra == \"dev\"", "chardet>=5.2", - "click>=8.1.8; extra == \"cli\"", + "click>=8.3.0; extra == \"cli\"", "flex~=6.14.1; extra == \"flex\"", "openapi-spec-validator~=0.7.1; extra == \"osv\"", - "packaging>=24.2", - "pytest-cov>=6.0; extra == \"dev\"", - "pytest>=8.3.5; extra == \"dev\"", - "requests>=2.32.3", - "ruamel.yaml>=0.18.10", - "sphinx>=8.1.3; extra == \"dev\"", - "swagger-spec-validator~=3.0.4; extra == \"ssv\"", - "towncrier>=24.8; extra == \"dev\"", - "tox>=4.23.2; extra == \"dev\"" + "orjson>=3.9; extra == \"fast\"", + "packaging>=25.0", + "requests>=2.32.5", + "ruamel.yaml>=0.18.16", + "swagger-spec-validator~=3.0.4; extra == \"ssv\"" ], "requires_python": ">=3.10", - "version": "25.4.8.0" + "version": "26.7.19.0" }, { "artifacts": [ @@ -3467,21 +3625,21 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", - "url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl" + "hash": "01c0891d7f9237d5e339f7d3e42cdae80b7534abb1c7c0e3352efba6231492f2", + "url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", - "url": "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz" + "hash": "9ec8a0ad96d5c56148b3f914aa79c1564c3fde5d2e6b876e7bc327e353cf8fa6", + "url": "https://files.pythonhosted.org/packages/7d/ea/39b988c938f75cb75d7045b5c69f8bfed47ee2152c8837fb403de29d6fb8/prompt_toolkit-3.0.53.tar.gz" } ], "project_name": "prompt-toolkit", "requires_dists": [ - "wcwidth" + "wcwidth>=0.1.4" ], - "requires_python": ">=3.8", - "version": "3.0.52" + "requires_python": ">=3.10", + "version": "3.0.53" }, { "artifacts": [ @@ -3661,248 +3819,248 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", - "url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl" + "hash": "346a034f080da3755d8e9cb5e00e8b07de1d39e4f6e2c87d8ab7cafa0b269a73", + "url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", - "url": "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz" + "hash": "51a9c5f7b2f8e636f04c6cada605d9b6a3bf1348fdf945a3d8869b19bba0ee08", + "url": "https://files.pythonhosted.org/packages/53/ef/fc4f868f4e2cee79f863883abffceff107875f569b848507319842d2a681/pydantic-2.13.5.tar.gz" } ], "project_name": "pydantic", "requires_dists": [ "annotated-types>=0.6.0", "email-validator>=2.0.0; extra == \"email\"", - "pydantic-core==2.46.4", + "pydantic-core==2.46.5", "typing-extensions>=4.14.1", "typing-inspection>=0.4.2", "tzdata; (python_version >= \"3.9\" and platform_system == \"Windows\") and extra == \"timezone\"" ], "requires_python": ">=3.9", - "version": "2.13.4" + "version": "2.13.5" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", - "url": "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl" + "hash": "b6acfb46a814762367fb7ba0828b0a17d441b92ce249a0e007474c9072662dda", + "url": "https://files.pythonhosted.org/packages/02/8e/b41c84c913f29973a268e6c2b5bbf13c95adb9956c126d10da11ba3b2bef/pydantic_core-2.46.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl" }, { "algorithm": "sha256", - "hash": "8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", - "url": "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl" + "hash": "4fdc8b93a41521988916eeaa271173fcca7fa0803d62f87675aac8dcec1c8e29", + "url": "https://files.pythonhosted.org/packages/09/f0/2a8ce3849e299d44e2d2c196b6082643a3235565a735cb51db7a6261f614/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" }, { "algorithm": "sha256", - "hash": "db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", - "url": "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl" + "hash": "d625a186a65201c23a9e3b8ed9c47e90a026e03256608cc91851c6709096844f", + "url": "https://files.pythonhosted.org/packages/0c/18/b70da8300e292df4099684ea11b1958043580d2f50d2dc8bf7e542bdd84a/pydantic_core-2.46.5-cp311-cp311-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", - "url": "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl" + "hash": "356c8368cbc321050b169595683a2e1d63413b1e0e2868b330af9fc14c616d3f", + "url": "https://files.pythonhosted.org/packages/13/5c/79fc00cb8f651d6061991de8d7cedf1c78c73cbd4862c42ef418f03b8bfa/pydantic_core-2.46.5-cp310-cp310-musllinux_1_1_armv7l.whl" }, { "algorithm": "sha256", - "hash": "962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", - "url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl" + "hash": "2bc9419666990c06d7397831f2126a1ecc3594aaa3ff7de5bf2d066802f4e07b", + "url": "https://files.pythonhosted.org/packages/1e/ee/ca3b7b3a4b3769ffe9ce9432a7c9be755de9593a46d3b0d54d0409323e44/pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_armv7l.whl" }, { "algorithm": "sha256", - "hash": "56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", - "url": "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl" + "hash": "413a717a410d0c817ef5b786a059415550b3794e1d0c2abffd9efb93a3d9f7b4", + "url": "https://files.pythonhosted.org/packages/1f/93/fd89e9ad49b1805ca94d24ce1088b7d305f05c35ffafcedb9819d03588a0/pydantic_core-2.46.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" }, { "algorithm": "sha256", - "hash": "c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", - "url": "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl" + "hash": "ab4b66edffb32d9e951efb3814bd104b8367a7501b81b955cacb5726d897389f", + "url": "https://files.pythonhosted.org/packages/20/21/22102e9950b3049526d20e811b95396508377d87651edd2b80d2b3d28659/pydantic_core-2.46.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl" }, { "algorithm": "sha256", - "hash": "133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", - "url": "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + "hash": "cd5214352ae68f3b5e9af7768bdc5253695ee069675db3480518420b3be881f2", + "url": "https://files.pythonhosted.org/packages/20/32/7d6ca365fadba186a0c8f85de1a701663bce81efd309d9479be58687622f/pydantic_core-2.46.5-cp311-cp311-musllinux_1_1_aarch64.whl" }, { "algorithm": "sha256", - "hash": "18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", - "url": "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl" + "hash": "53feb344243bb9510a9dec7bf3cf1b64d88a98af5dc7872a5160465f8b198c8e", + "url": "https://files.pythonhosted.org/packages/24/98/7b76b1ad10a19a617a52aaa1d80e159115af939b095e86f8e756fd52e0df/pydantic_core-2.46.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl" }, { "algorithm": "sha256", - "hash": "7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", - "url": "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + "hash": "fc5d783bd4a2387e97b8a2d5ec781cfb92b3d893bf82370548e99db5915935d3", + "url": "https://files.pythonhosted.org/packages/30/c8/47c79b756f12f85e8b0fbdb2b495f6b6eb32e6c98a4beae7a570a0b7c63c/pydantic_core-2.46.5-cp310-cp310-musllinux_1_1_aarch64.whl" }, { "algorithm": "sha256", - "hash": "f47286a97f0bc9b8859519809077b91b2cefe4ae47fcbf5e466a009c1c5d742b", - "url": "https://files.pythonhosted.org/packages/4e/74/76223bfb117b64af743c9b6670d1364516f5c0604f96b48f3272f6af6cc6/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl" + "hash": "850a08d167dde16db8702c274f320c7be9d7da6f6dff2b58b18f9e815bd94f5b", + "url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" }, { "algorithm": "sha256", - "hash": "da4b951fe36dc7c3a1ccb4e3cd1747c3542b8c9ceede8fc86cae054e764485f5", - "url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl" + "hash": "6d30e1a4f138b8951063e9a394752a9179b51da288ffa507b1e659222f4c1793", + "url": "https://files.pythonhosted.org/packages/3d/93/ce93aa030ab6bac4683ba8861e7baad89dd24b02e66b8801a0e4f6a00311/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl" }, { "algorithm": "sha256", - "hash": "3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", - "url": "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl" + "hash": "4dedce55295becb61921e386b99d4f2706045306e7fa52249a33004c837379fb", + "url": "https://files.pythonhosted.org/packages/4a/77/ca2f8e997d9bfdb32205297aff38f210f398822d895b1af1b59fd9df9c13/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" }, { "algorithm": "sha256", - "hash": "0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", - "url": "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl" + "hash": "aca6c767f552b21b10f774aeac128e828eafb796adfa1b666a18bf6321453c3a", + "url": "https://files.pythonhosted.org/packages/4a/ea/f86073830e35d508cc8ddf9c3d9e6e6840fcb88d34bf726b0b4710186f27/pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", - "url": "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + "hash": "3a3e26b6a8274211bddee2d0e4d0d42778f17a34510f49d2ec44b58abfc41736", + "url": "https://files.pythonhosted.org/packages/4a/f7/1ab28093c09032ddce7c92c7a55d503b6ecd70f42c32492946c1cb5477b1/pydantic_core-2.46.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl" }, { "algorithm": "sha256", - "hash": "bb63e0198ca18aad131c089b9204c23079c3afa95487e561f4c522d519e55aba", - "url": "https://files.pythonhosted.org/packages/64/ba/bfb1d928fd5b49e1258935ff104ae356e9fd89384a55bf9f847e9193ad40/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + "hash": "c3471e5c4a949c26ec00a77f01df59096aa9495877de76fd60a980f8ee6be461", + "url": "https://files.pythonhosted.org/packages/5c/fa/605e2b127ee30dbf4b1da9da4843587cf2b2d16486c241cc7a5be2d2c1bd/pydantic_core-2.46.5-cp310-cp310-manylinux_2_31_riscv64.whl" }, { "algorithm": "sha256", - "hash": "9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", - "url": "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl" + "hash": "1e449def1945a462c464331254e5a44fca7c3b4f9aedf59ec2f50f8066dd8e25", + "url": "https://files.pythonhosted.org/packages/6f/45/8e59dab6acf8d35f02f0a958980074f31038968bdb2c983fcae9d1efee03/pydantic_core-2.46.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl" }, { "algorithm": "sha256", - "hash": "8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", - "url": "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl" + "hash": "efd62a42486f1bda5d24cb4f63d15a3c7768375fe83d36f9417b4ad7a2fb20b3", + "url": "https://files.pythonhosted.org/packages/70/0a/644597d84ab400e50609c192120b85c9681c22d3a20461b9060a79be0a7a/pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_aarch64.whl" }, { "algorithm": "sha256", - "hash": "17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", - "url": "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl" + "hash": "657b40d6240c0a7b6a64b30f22d1e3aa631c7e846c621b0c0f6d1d75e2e15ea6", + "url": "https://files.pythonhosted.org/packages/74/6b/8f79692844269427abb3e4dd9e68edfcbe65ae25527d99183214de716c59/pydantic_core-2.46.5-cp310-cp310-macosx_10_12_x86_64.whl" }, { "algorithm": "sha256", - "hash": "daa27d92c36f24388fe3ad306b174781c747627f134452e4f128ea00ce1fe8c4", - "url": "https://files.pythonhosted.org/packages/72/04/2beacf7e1607e93eefe4aed1b4709f079b905fb77530179d4f7c71745f22/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_aarch64.whl" + "hash": "d925f3d9afd05a8c0fb3a1031463a8d59ebe5e2afad297e29c78be19e13b4e62", + "url": "https://files.pythonhosted.org/packages/7b/a0/9ff22b797724262da14427abaed4dd1d864a139693fc5e7809114376a716/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl" }, { "algorithm": "sha256", - "hash": "c1747f85cee84c26985853c6f3d9bd3e75da5212912443fa111c113b9c246f39", - "url": "https://files.pythonhosted.org/packages/7c/af/0f7a5b85fec6075bea96e3ef9187de38fccced0de92c1e7feda8d5cc7bb9/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_x86_64.whl" + "hash": "5f93c5fe914d75fbec9a49209b00da5f08e9e467d69da2b1510c81940cfd10be", + "url": "https://files.pythonhosted.org/packages/7d/1d/02eb35761c51f2f7b1b042d6ab4cda6600f0c8c88a2243b3f734376201e5/pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl" }, { "algorithm": "sha256", - "hash": "f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", - "url": "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + "hash": "b9fe6fb92520e3fd61f2e49000b6911b188824f089b75973ea06d6267f0b476d", + "url": "https://files.pythonhosted.org/packages/82/3f/76358795aa7a8c6d4f36e2cb828ad1c90ee118e1393a9281664f5aade9d4/pydantic_core-2.46.5-cp312-cp312-macosx_10_12_x86_64.whl" }, { "algorithm": "sha256", - "hash": "c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", - "url": "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl" + "hash": "b98134087d9de723658d17a42c7d0da8d6e2ef08015dee7dc93889047315f5e4", + "url": "https://files.pythonhosted.org/packages/87/46/ac0dc8bdd9e6048183a14eb127764e7ad9240021c17513074a4711b0e31e/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl" }, { "algorithm": "sha256", - "hash": "8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", - "url": "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + "hash": "8feeac04b5794e513e710af2f9c87d49f31a6dc47967bb264a1fed61a8989bec", + "url": "https://files.pythonhosted.org/packages/8a/f9/548a5bb9d4ba8cd26e26daf48052236f6b38bb61e7b7241fbc3c995719eb/pydantic_core-2.46.5-cp311-cp311-musllinux_1_1_x86_64.whl" }, { "algorithm": "sha256", - "hash": "fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", - "url": "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" + "hash": "c7ea57fc63aa7da93a1bd2d644e6577befae10c52c4e36377635eea1056a74f5", + "url": "https://files.pythonhosted.org/packages/92/b1/e781d357ebe09fc929f995700f1b3503e8897f1cece183ecb1300d4d67e9/pydantic_core-2.46.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl" }, { "algorithm": "sha256", - "hash": "4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", - "url": "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl" + "hash": "9f47b8a949e60f027f0aa0a6f6c7b7e9c55cbf4380d10b344e282fa4e7ab1e1b", + "url": "https://files.pythonhosted.org/packages/a0/53/bd12e1a9255df4edee00353778e2614b5346265d51e1567ab72153e803a2/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl" }, { "algorithm": "sha256", - "hash": "62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", - "url": "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz" + "hash": "a1dee1b804ff4d11c663636cf15d2ea47e9f79cd56c033fb1cbf08924842a48f", + "url": "https://files.pythonhosted.org/packages/a2/b6/81d2d19ea0be2c03664381b59f65fa72fc7969decedae00bc2c4ad835708/pydantic_core-2.46.5-cp311-cp311-macosx_10_12_x86_64.whl" }, { "algorithm": "sha256", - "hash": "19e51f073cd3df251856a8a4189fbdf1de4012c3ebacfb1884f94f1eb406079f", - "url": "https://files.pythonhosted.org/packages/9e/29/d2b9fd9f539133548eaf622c06a4ce176cb46ac59f32d0359c4abc0de047/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_armv7l.whl" + "hash": "a2468d93d181667a7abd66e1b64bb9f76f361b0fef8faddf687456453576f5ee", + "url": "https://files.pythonhosted.org/packages/ab/9a/095d557bb492c90cd8a70a6dd048bf793d433d03d86c81c11e912e4cd049/pydantic_core-2.46.5-cp311-cp311-manylinux_2_31_riscv64.whl" }, { "algorithm": "sha256", - "hash": "b078afbc25f3a1436c7a1d2cd3e322497ee99615ba97c563566fdf46aff1ee01", - "url": "https://files.pythonhosted.org/packages/a9/da/0a422b57bf8504102bf3c4ccea9c41bab5a5cee6a54650acf8faf67f5a24/pydantic_core-2.46.4-cp310-cp310-manylinux_2_31_riscv64.whl" + "hash": "10416c15b8839ecc4ef4d0885da76da6fd0f67333a0eb8aff6d93c4b8f2910fc", + "url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz" }, { "algorithm": "sha256", - "hash": "d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", - "url": "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl" + "hash": "eb7d8d0e5886a89a55d2eef490e272fa965a9d57c6b29a5b5088a7997ec2cad1", + "url": "https://files.pythonhosted.org/packages/b4/72/dd1a29853cf6d22a1ebd9e3baf0239cbc57d2d16caff36a89e38eb9b1db3/pydantic_core-2.46.5-cp310-cp310-musllinux_1_1_x86_64.whl" }, { "algorithm": "sha256", - "hash": "b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", - "url": "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl" + "hash": "701b2e04b560eeb4bddf7a25ab8ca476176e34fdbd9a0e18196f0d12d4685f0b", + "url": "https://files.pythonhosted.org/packages/bb/d7/fc36240d7791ce90939e51608568c33bfdae26202016f9770c229a487d86/pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl" }, { "algorithm": "sha256", - "hash": "e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", - "url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl" + "hash": "ecb42011e12ee19cafbc312887cbf3546959fe02fbad44f272d4be5baa997615", + "url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "ea793e075b70290d89d8142074262885d3f7da19634845135751bd6344f73b50", - "url": "https://files.pythonhosted.org/packages/b5/2f/e90b63ee2e14bd8d3db8f705a6d75d64e6ee1b7c2c8833747ce706e1e0ce/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl" + "hash": "816ff0a6550ffc06c098ccd2e0698600f9aa7da192a79eaa6f9af504a35db869", + "url": "https://files.pythonhosted.org/packages/c0/02/7f6156ffc926857f1c37c07d9a388682865a81830ab6a1b637082c25e399/pydantic_core-2.46.5-cp312-cp312-manylinux_2_31_riscv64.whl" }, { "algorithm": "sha256", - "hash": "395aebd9183f9d112f569aeb5b2214d1a10a33bec8456447f7fbdfa51d38d4cd", - "url": "https://files.pythonhosted.org/packages/ba/1e/acc4d70f88a0a277e4a1fa77ebb985ceabaf900430f875bf9338e11c9420/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + "hash": "0fc5be0abd4a407e200d844b404e33639a554e7bd0d448e7b9ae181be4789ac2", + "url": "https://files.pythonhosted.org/packages/c0/a4/eb9409ec0736e50aa70a412f16c204ed149516846912f7e6724d4c73ee53/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" }, { "algorithm": "sha256", - "hash": "f747929cf940cddb5b3668a390056ddd5ba2e5010615ea2dcf4f9c4f3ab8791d", - "url": "https://files.pythonhosted.org/packages/bd/2a/2ac13c3af305843e23c5078c53d135656b3f05a2fd78cb7bbbb12e97b473/pydantic_core-2.46.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl" + "hash": "2d330aaba8621b1edcec8ae2c4050f63b84ccf6d98723a8f212e9684713abf0e", + "url": "https://files.pythonhosted.org/packages/c2/d7/ad493864a7fb21c0c4df98f965e2db430cb25a9d7369b5778d5016c09fd9/pydantic_core-2.46.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl" }, { "algorithm": "sha256", - "hash": "905a0ed8ea6f2d61c1738835f99b699348d7857379083e5fc497fa0c967a407c", - "url": "https://files.pythonhosted.org/packages/cb/7b/848732968bc8f48f3187542f08358b9d842db564147b256669426ebb1652/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" + "hash": "e652ab17569c94bff5475520f907b7148b8c24036a8ebbe5cf7cf7493d28579a", + "url": "https://files.pythonhosted.org/packages/c4/c2/339de5bef7be36301a2231eaa52e62163742c2281f11b5f4892bc79785cd/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", - "url": "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl" + "hash": "18a09e1e1011b462f2e32774f25859ef1223d5c2b0546a633cf56654710721e0", + "url": "https://files.pythonhosted.org/packages/ce/52/39fa1f451486019524ca685020390e7ca351832fd874530ba30c8628e6dc/pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_x86_64.whl" }, { "algorithm": "sha256", - "hash": "fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", - "url": "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl" + "hash": "49776eab08766a08dfff7012f8b422dcd7e25e43b316eedf0477c24fcfa84b7c", + "url": "https://files.pythonhosted.org/packages/cf/bc/3fa2d76b83162820a17da7f645b28d1cba99fc8e1e5fc6517067ec450fa1/pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" }, { "algorithm": "sha256", - "hash": "a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", - "url": "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl" + "hash": "a445486499897b88a7d6c310c88ed64dd37b1b59bfd7ae9107490bbb362f47d6", + "url": "https://files.pythonhosted.org/packages/d5/a5/e1d4dc5180dd887a9522efc1f8716b8692b7606b1d3273d7862eaf66be44/pydantic_core-2.46.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl" }, { "algorithm": "sha256", - "hash": "9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", - "url": "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl" + "hash": "200aa3dc9f8d54f0754f43247c0bad0999fdcfbfd2488384dd44f37279271fe6", + "url": "https://files.pythonhosted.org/packages/d7/41/f7f312751ebc6d6767da91964a9c7954c18e226a1720ab234e3dfb9d6c17/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "a396dcc17e5a0b164dbe026896245a4fa9ff402edca1dff0be3d53a517f74de4", - "url": "https://files.pythonhosted.org/packages/e7/08/f1ba952f1c8ae5581c70fa9c6da89f247b83e3dd8c09c035d5d7931fc23d/pydantic_core-2.46.4-cp310-cp310-macosx_10_12_x86_64.whl" + "hash": "337639ba62a11acde6ef3aeb08c8ea755f8ef1fe5e513356c0f36a2b0d7568b0", + "url": "https://files.pythonhosted.org/packages/d8/18/87aefa427d191e6d3ab1447f1efc1cdcac86af1069239b133e8a0fd7f7c9/pydantic_core-2.46.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", - "url": "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl" + "hash": "a39ac25a9a2fa4072efdb429833c4a4c8009a51ff9eea3eeae131713cd27991e", + "url": "https://files.pythonhosted.org/packages/db/50/26b091836076ce4cb2fac264186936acc069e0595772cfd02a563bc4761a/pydantic_core-2.46.5-cp312-cp312-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", - "url": "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" + "hash": "4f8507560a9284e1370bb048ed4282012fbef4e8d109875b95e884d228552061", + "url": "https://files.pythonhosted.org/packages/e7/1a/0d590341b6ffa4b4aca83508e6b8db4761aaeacfc15a25ca3815876d4797/pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" }, { "algorithm": "sha256", - "hash": "aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", - "url": "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl" + "hash": "9432f3598db432cb51c5b37fdbf29a60fcccc79e30d37a05022776a6bc4ab689", + "url": "https://files.pythonhosted.org/packages/f8/09/eb9a6aa57f22fd1541a9c0aa2a1f3aeef3ec65347d33e10a6da2f43e0ee9/pydantic_core-2.46.5-cp311-cp311-musllinux_1_1_armv7l.whl" } ], "project_name": "pydantic-core", @@ -3910,19 +4068,19 @@ "typing-extensions>=4.14.1" ], "requires_python": ">=3.9", - "version": "2.46.4" + "version": "2.46.5" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "a20c97b37910b6550d5ea50fbcc2d4187defe58cd57070b73863d069419c9440", - "url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl" + "hash": "0ba092c291c94baceb5eff768aa0d56400a457585bc0175925a5a5510303da42", + "url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f", - "url": "https://files.pythonhosted.org/packages/5c/b5/8f48e906c3e0205276e8bd8cb7512217a87b2685304d64be27cad5b3019f/pydantic_settings-2.14.2.tar.gz" + "hash": "694b793e84f766ba76a90ebdefc01d0a9a045dab0382bee70393da93712ad117", + "url": "https://files.pythonhosted.org/packages/68/ca/31c57507b13119d7d3cfa1576dad2911a4861e3be07b579395f4e9d393f9/pydantic_settings-2.15.0.tar.gz" } ], "project_name": "pydantic-settings", @@ -3935,11 +4093,10 @@ "python-dotenv>=0.21.0", "pyyaml>=6.0.1; extra == \"yaml\"", "tomli>=2.0.1; extra == \"toml\"", - "types-boto3[secretsmanager]; extra == \"aws-secrets-manager\"", "typing-inspection>=0.4.0" ], "requires_python": ">=3.10", - "version": "2.14.2" + "version": "2.15.0" }, { "artifacts": [ @@ -3999,13 +4156,13 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", - "url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl" + "hash": "2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", + "url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", - "url": "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz" + "hash": "610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", + "url": "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz" } ], "project_name": "pygments", @@ -4013,7 +4170,7 @@ "colorama>=0.4.6; extra == \"windows-terminal\"" ], "requires_python": ">=3.9", - "version": "2.20.0" + "version": "2.21.0" }, { "artifacts": [ @@ -4289,13 +4446,13 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "7237cb47985ccf5da512106ddb2731e4f9cefec00991f76c054488eb95fb1a2d", - "url": "https://files.pythonhosted.org/packages/dd/9f/4da6a1b9611af2397289b77d6fd08f5fe8f1f34dabc3bf85b0638d655e64/pyspnego-0.12.1-py3-none-any.whl" + "hash": "04e7c9260ced15197b3f42b891ffa30fa98c37bb09372c5c2bf927bcdfe30b53", + "url": "https://files.pythonhosted.org/packages/0e/8c/3d0154b8781a371ef1b791063da5a223187dd17738c5b188edc5e9657f9a/pyspnego-0.12.2-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "ff4fb6df38202a012ea2a0f43091ae9680878443f0ea61c9ea0e2e8152a4b810", - "url": "https://files.pythonhosted.org/packages/7d/84/58577bd1b14293650879de0579ec263a1d8350f1d6d227226cf776b5a6a6/pyspnego-0.12.1.tar.gz" + "hash": "448a491a9bf0e5fb957567fe46e6809fa836aa40dfcccebcc740bb64acb1be1c", + "url": "https://files.pythonhosted.org/packages/03/c4/790211e7a2180509dc29137c488c7b038ef89bdf83db0ce4da802f64f9d4/pyspnego-0.12.2.tar.gz" } ], "project_name": "pyspnego", @@ -4304,10 +4461,10 @@ "gssapi>=1.6.0; sys_platform != \"win32\" and extra == \"kerberos\"", "krb5>=0.3.0; sys_platform != \"win32\" and extra == \"kerberos\"", "ruamel.yaml; extra == \"yaml\"", - "sspilib>=0.3.0; sys_platform == \"win32\"" + "sspilib>=0.5.0; sys_platform == \"win32\"" ], "requires_python": ">=3.9", - "version": "0.12.1" + "version": "0.12.2" }, { "artifacts": [ @@ -4402,22 +4559,21 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "810958f66a91afb1a1e2ae83089d8dc1cd2437ac96b12963042fbb9fb4d16af0", - "url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl" + "hash": "e9f3475fa0a42927f5e370d721de9c2d785616a06a4c506712d6cb8055e37c84", + "url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "4dafd46a9a600f65d822b8f605133ecf5b3e1941ebb3588e943b4e3eb71a5a3f", - "url": "https://files.pythonhosted.org/packages/8c/c9/93ad2ba2413057ee694884b88cf7467a46c50c438977720aeac26e73fdb7/pytest-forked-1.6.0.tar.gz" + "hash": "00f2bee51612f29b8e6b81eed2c3b2975e824c2693394f5bdaf7a1369078ba5f", + "url": "https://files.pythonhosted.org/packages/99/92/98bd460b998f9ec053acba2e3efbbca12a9a408ec8648bd55abd2df784f0/pytest_forked-1.7.5.tar.gz" } ], "project_name": "pytest-forked", "requires_dists": [ - "py", - "pytest>=3.10" + "pytest>=7" ], - "requires_python": ">=3.7", - "version": "1.6.0" + "requires_python": ">=3.10", + "version": "1.7.5" }, { "artifacts": [ @@ -4490,45 +4646,33 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "abebe9120b43453b68c908acfb1e72a19d1a959ed2cb620ad38fc57d08056dbe", - "url": "https://files.pythonhosted.org/packages/9d/ae/84bc0d2440c95772272bb6f4b3d09ccf08b2898fce89b3d4f969a9fc74e9/python_discovery-1.4.4-py3-none-any.whl" + "hash": "d4e244cf17b8b29819ed78003d55fbacf86eda23425b075454fff9271b79377a", + "url": "https://files.pythonhosted.org/packages/43/5e/21abf578182fb15006a57faf3711a1e659e29d600d19b6e557eae908c81d/python_discovery-1.6.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "5cad33982d412c1f3ffb8f9ca4ea292c9680bca3942451d30b69c37fce53a4a3", - "url": "https://files.pythonhosted.org/packages/4c/81/58c70036dffeccb7fe7d79d6260c69f7a28272bbd3909c29a01ea9422744/python_discovery-1.4.4.tar.gz" + "hash": "6393b4eae1be8b2182670635e7baff89ac21cb9f8e86fd1ff40c7b1144febb4c", + "url": "https://files.pythonhosted.org/packages/91/96/0f93e27c9f60a650838f2118159aa115fd5732c0716247917b7ba7ede665/python_discovery-1.6.0.tar.gz" } ], "project_name": "python-discovery", "requires_dists": [ - "covdefaults>=2.3; extra == \"testing\"", - "coverage>=7.5.4; extra == \"testing\"", - "filelock>=3.15.4", - "furo>=2025.12.19; extra == \"docs\"", - "platformdirs<5,>=4.3.6", - "pytest-mock>=3.14; extra == \"testing\"", - "pytest>=8.3.5; extra == \"testing\"", - "setuptools>=75.1; extra == \"testing\"", - "sphinx-autodoc-typehints>=3.6.3; extra == \"docs\"", - "sphinx>=9.1; extra == \"docs\"", - "sphinxcontrib-mermaid>=2; extra == \"docs\"", - "sphinxcontrib-towncrier>=0.4; extra == \"docs\"", - "towncrier>=25.8; extra == \"docs\"" + "filelock>=3.15.4" ], "requires_python": ">=3.8", - "version": "1.4.4" + "version": "1.6.0" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", - "url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl" + "hash": "904552145e8bfed22162c09dab1c2b9b54fefa7b23ba780f4f26ca0316b0f0d9", + "url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", - "url": "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz" + "hash": "a20a594dabeaa385725aa239d5244871c143ecb356add8a20fcf23773a6c3a35", + "url": "https://files.pythonhosted.org/packages/6a/53/ed9d74092561d4b01a2ef1349d52cdbc135e526c245f366b089cfca6de49/python_dotenv-1.2.3.tar.gz" } ], "project_name": "python-dotenv", @@ -4536,44 +4680,25 @@ "click>=5.0; extra == \"cli\"" ], "requires_python": ">=3.10", - "version": "1.2.2" + "version": "1.2.3" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "132994765cf75bf44554be9aa49b06ef2345d23661a96720262716438141b6b2", - "url": "https://files.pythonhosted.org/packages/27/be/0631a861af4d1c875f096c07d34e9a63639560a717130e7a87cbc82b7e3f/python_json_logger-4.1.0-py3-none-any.whl" + "hash": "158a52126fcd6869e09574d2b66272666f3dc8f468c62637ef9a1fa883719cb9", + "url": "https://files.pythonhosted.org/packages/dc/55/6467fde553886cb293e41538f3a8b4e4fd4688c6df242cf982162d8367fb/python_json_logger-4.2.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "b396b9e3ed782b09ff9d6e4f1683d46c83ad0d35d2e407c09a9ebbf038f88195", - "url": "https://files.pythonhosted.org/packages/f7/ff/3cc9165fd44106973cd7ac9facb674a65ed853494592541d339bdc9a30eb/python_json_logger-4.1.0.tar.gz" + "hash": "e371ebe22ec01e289850102091a2b1f6fc9e655c7f1f5f29073936756c290afa", + "url": "https://files.pythonhosted.org/packages/21/25/5473e46b179f8e8b4ad3aeeb36773d1701b7770eaf5e5bc2025c7303b598/python_json_logger-4.2.0.tar.gz" } ], "project_name": "python-json-logger", - "requires_dists": [ - "black; extra == \"dev\"", - "build; extra == \"dev\"", - "freezegun; extra == \"dev\"", - "mdx_truly_sane_lists; extra == \"dev\"", - "mike; extra == \"dev\"", - "mkdocs-awesome-pages-plugin; extra == \"dev\"", - "mkdocs-gen-files; extra == \"dev\"", - "mkdocs-literate-nav; extra == \"dev\"", - "mkdocs-material>=8.5; extra == \"dev\"", - "mkdocs; extra == \"dev\"", - "mkdocstrings[python]; extra == \"dev\"", - "msgspec; implementation_name != \"pypy\" and extra == \"dev\"", - "mypy; extra == \"dev\"", - "orjson; implementation_name != \"pypy\" and extra == \"dev\"", - "pylint; extra == \"dev\"", - "pytest; extra == \"dev\"", - "tzdata; extra == \"dev\"", - "validate-pyproject[all]; extra == \"dev\"" - ], + "requires_dists": [], "requires_python": ">=3.10", - "version": "4.1.0" + "version": "4.2.0" }, { "artifacts": [ @@ -4619,19 +4744,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126", - "url": "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl" + "hash": "dd95840dd199baea12d9cc096a1d452caa6596a1c1e4b5f3dbd1541855d5e815", + "url": "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a", - "url": "https://files.pythonhosted.org/packages/ff/46/dd499ec9038423421951e4fad73051febaa13d2df82b4064f87af8b8c0c3/pytz-2026.2.tar.gz" + "hash": "2211d3fcf9a797d3405cac96ac7f61d80e6a644f72a3309607282fe8a2010c5d", + "url": "https://files.pythonhosted.org/packages/fb/48/fb042503b6ca6cd271261dc559fd6432f7d8c713153e9ec5c591af4dfc1c/pytz-2026.3.post1.tar.gz" } ], "project_name": "pytz", "requires_dists": [], "requires_python": null, - "version": "2026.2" + "version": "2026.3.post1" }, { "artifacts": [ @@ -4795,13 +4920,13 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "47daa35a058c23468d6437f17a8c76882cb316b838ef763036af99b96cedd743", - "url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl" + "hash": "a4fe1aac3d3b3cc791d4b3d5931c5a956045dc951ee74d1c913ee3ac4d2ee9fb", + "url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "afc5a7a2f5a084f5b1880dec548dd45be17db7e43c82a30d84f952aefb05cfb0", - "url": "https://files.pythonhosted.org/packages/cc/c3/928b290c2c0ca99ab96eea5b4ff8f30be8112b075301a7d3ba214a3c8c12/redis-8.0.1.tar.gz" + "hash": "6e1a19beef9225c83efd689c7e6b7da2d5215b1f42cd13b7fc3714d0a09c7b25", + "url": "https://files.pythonhosted.org/packages/a8/99/604f0b666d4c616d891cf77ebb9db6bb21601344c051aebf1b72b9ff915f/redis-8.1.0.tar.gz" } ], "project_name": "redis", @@ -4819,7 +4944,7 @@ "xxhash~=3.6.0; extra == \"xxhash\"" ], "requires_python": ">=3.10", - "version": "8.0.1" + "version": "8.1.0" }, { "artifacts": [ @@ -5378,154 +5503,154 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "2ce92b3748f02423e26d2bfb636fb9d7a8f67c8f5854dcae69d350d123b2eee2", - "url": "https://files.pythonhosted.org/packages/ce/6a/8b74c52ffd33dbbde00fe7251fee6a0acdc8cea33f7a43805aed258fb79b/simplejson-4.1.1-py3-none-any.whl" + "hash": "93f95f6769f37f4c3763666950b23bf9b9230b60bf1d718845e92db2ebcbf32d", + "url": "https://files.pythonhosted.org/packages/95/e2/7f47df8fbd3d9c35902b76c242e21759a27d6e8c030c901c4f0ad93dd10b/simplejson-4.1.2-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "2785ff8edc0e28bf773a32543a6bbed46351453c997b3f6709c744e3c2f7eabb", - "url": "https://files.pythonhosted.org/packages/05/88/bd8aad36b451ffb0e0a3f721d695a88befa6d1ac7d1e02ae788ca7ff4029/simplejson-4.1.1-cp312-cp312-musllinux_1_2_x86_64.whl" + "hash": "81c1746fcf232faec2b5b7160f8e249bb5826234286f861b7aa8e80faa0d98c4", + "url": "https://files.pythonhosted.org/packages/0b/e7/43a5331fa3918b239621a8258993e3ad5217861b345c6464ecf0a84076be/simplejson-4.1.2-cp310-cp310-musllinux_1_2_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "45ec18e337fec538b7e902d489505c450b2454653d1290f3f50385e6fd8aa607", - "url": "https://files.pythonhosted.org/packages/0c/b6/156a8de1e1b47694f0e7de6675866936608d45dc68388fd017d36f8693be/simplejson-4.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + "hash": "8842cae188daf4f7ab93cca85156bf57a1f5fe24379b9e20040da7d3a829ba64", + "url": "https://files.pythonhosted.org/packages/0f/e9/4d6181137f23088baa8abdc2a6e01a4eb872865532265cc4fae23f7dc193/simplejson-4.1.2-cp311-cp311-macosx_10_9_universal2.whl" }, { "algorithm": "sha256", - "hash": "c08eb9f7a90f77ae470e19a07472e9a79ebc0d1c2315d86a72767665bd5ba79f", - "url": "https://files.pythonhosted.org/packages/0e/2a/54837395a3487c725669428d513293612a48d82b95a0642c936932e5d898/simplejson-4.1.1.tar.gz" + "hash": "438aa043f693af285aaeea2ce72fa4a45b96d1532a1431d937577083fe13254d", + "url": "https://files.pythonhosted.org/packages/1b/47/53185d6bfa624dec5a9d1b10d4a9ca46b29124bc5695a1f33715a66606a1/simplejson-4.1.2-cp312-cp312-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "c7494c75b95171194f965ea609e97081837a26494d91dcc046ad27dd9c3503e2", - "url": "https://files.pythonhosted.org/packages/1d/d6/a2a7a482fa43aaeaefc001491d381960f5e685ee4645343e0e037cebb57c/simplejson-4.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + "hash": "6f155b6b58725890f9a9d915b9e7108eaf7080542ab5fd8e31e9a5908ecf2c7d", + "url": "https://files.pythonhosted.org/packages/1e/5b/fa612786782b09373339ed89f1e80b0d667fdbb372534f0250bbceae1db8/simplejson-4.1.2-cp310-cp310-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "2867c64d92abd1992c15666fae198203093f593e43d6b81adf176bae530d493a", - "url": "https://files.pythonhosted.org/packages/1e/25/39013ffe279d90093ec1c848565b3683c586906c10fa55d9000ec29d046b/simplejson-4.1.1-cp311-cp311-macosx_10_9_universal2.whl" + "hash": "d63bc3adb552480c890b9ff8fc119e8997b414a8cb68b888761f5dfefafd2bf8", + "url": "https://files.pythonhosted.org/packages/20/dc/ad9aa843de7f9cb74a924f79a6d53986b3351206b792ccf27d6a4a92b745/simplejson-4.1.2-cp311-cp311-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "4c44ef6b02a4eb67ed17a72342341792149b3ff46f15426c26e970e49addf327", - "url": "https://files.pythonhosted.org/packages/34/09/69e331e3994b1ed9be6ce9ace4ade704e7ed503edf869929ca7bb404eda8/simplejson-4.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "a83dd08a7cbe770e9d14be2dbedde77890477cc44e804582ef69cbd8a1c834b2", + "url": "https://files.pythonhosted.org/packages/2c/67/dff3c64269e352dbec781f1920c4422816a675d1953b62d18c100ddf4931/simplejson-4.1.2-cp311-cp311-macosx_10_9_x86_64.whl" }, { "algorithm": "sha256", - "hash": "0e4b23f71dd781f8830f1663dc01a4944d3dbf87a1f93d78fba1cf64722d0ccf", - "url": "https://files.pythonhosted.org/packages/38/94/8d6f515b827b0f7881a49c8c1ac6920b7ae9428939ef04238c973278b42a/simplejson-4.1.1-cp311-cp311-musllinux_1_2_aarch64.whl" + "hash": "3b8d4ff4cd6e8cdab666431169378820cb4570fa06cb74d3f0cc165aa5434b62", + "url": "https://files.pythonhosted.org/packages/30/00/7876a15fbecac1d4653ce2af0b446fa1308af8d6f3f802e2e7019698b46d/simplejson-4.1.2-cp312-cp312-musllinux_1_2_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "7f61eefab86235c800e7f4e37d977080ec424bb2bf0b74e95a2d17ecb48eac0a", - "url": "https://files.pythonhosted.org/packages/47/da/3ba5e87e917094961e7b51b541c88f735f1ca37d580ac78a9302b468f64e/simplejson-4.1.1-cp310-cp310-macosx_10_9_universal2.whl" + "hash": "5589cd313b201cb915d796b6f9ad372b2285672a6bc9e9833bf23011297b38f6", + "url": "https://files.pythonhosted.org/packages/35/0c/eced473e9bdd47c741dcdfc1e309d243be970a9bf432d3f2e274f66f111d/simplejson-4.1.2-cp311-cp311-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "a9ab55d2459f6d0fdf9984a7a0fb0280dae12979f4fcc3171f5096a4fcf5fafe", - "url": "https://files.pythonhosted.org/packages/4a/3e/82c8997c4ef2ef6c832fbfc3bb2ed14a212616a284100af03b552ea7e072/simplejson-4.1.1-cp310-cp310-musllinux_1_2_x86_64.whl" + "hash": "ddbdfe504c8ab09443856544fb744dc881701b0289da68e3e6904ec1745ff4a6", + "url": "https://files.pythonhosted.org/packages/3d/57/8473951699049947b25c64e02f5897e37a4598a269a217d25e44bc35c571/simplejson-4.1.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" }, { "algorithm": "sha256", - "hash": "e294e33dbf316a9bbdd4030d46503c9b0f19470ae7ad6af5bae6c426bc2e869f", - "url": "https://files.pythonhosted.org/packages/4e/a2/6eebfb99dedc139f549200f61ade6d1890ac5707c5d427bdfa6fe39c9313/simplejson-4.1.1-cp311-cp311-macosx_11_0_arm64.whl" + "hash": "0247d71cd72dbd4f1b9dc3db9a1e333b74cbb35ee4f9287230de97de4cc03eb6", + "url": "https://files.pythonhosted.org/packages/49/77/31a91f9e237591802d72d9ff9922c4c88f94eef34ade81d6e36769d70ba6/simplejson-4.1.2-cp312-cp312-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "82bfca2b85a34178c25829c703f0a9e9f113a5af7539285bd3efb583a0bf1ba3", - "url": "https://files.pythonhosted.org/packages/5d/40/ed806f24afef295c1032448f5ff6f6f2979392d5645ddb9f4fed7f38194d/simplejson-4.1.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" + "hash": "fd305a4699fc949ba6089ddfd17f582ce7c4a5d85e5601c44b42e35ebf521174", + "url": "https://files.pythonhosted.org/packages/4e/c4/75efe79679235b74ed3ff9ef91421bf4d57ca9e7ffa84543975f3fd833af/simplejson-4.1.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "19040a17154dc03d289bab68d73ce0a6a0be01de30c584bbdd93490bead14b22", - "url": "https://files.pythonhosted.org/packages/60/25/e90998fe8e480eb43b966c09e835379887d427567ebd496563d3b1e16b19/simplejson-4.1.1-cp312-cp312-macosx_10_13_universal2.whl" + "hash": "8c9850876ecf19c044d1f048fcb176997c0eb47ec9a9ba85d32d995fcf797168", + "url": "https://files.pythonhosted.org/packages/52/76/b3fe036455beda5e0ed0dd84dba674deb2c7b60f977b711394e5913250d9/simplejson-4.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "2e708d373a10e4378ef2d59f8361850c7150fd907ed49efe49bc5492160476d1", - "url": "https://files.pythonhosted.org/packages/76/0e/7f5a59d29426b062d5928fb88b403c3f797129d53be7102f955dbe51aa44/simplejson-4.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" + "hash": "99a76da628af68a90c906e5c0dc7da784eb1ceff7e631aa7c43745b3e6d426a7", + "url": "https://files.pythonhosted.org/packages/57/bf/bd3582de3eeadd0f7d2864f37a91389f34e19d66391e9ef94bcf028be844/simplejson-4.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "980fc33353f81fd12d8c49d44f8c2760d1dc8192285e627c5180d141035b228a", - "url": "https://files.pythonhosted.org/packages/78/18/9943db224dd4d5fa3c090c3e56a94c37b254338c83995ec5680285111c40/simplejson-4.1.1-cp312-cp312-musllinux_1_2_aarch64.whl" + "hash": "5d7426d083647d034debf499094637f63257b72b9899c81aa8196444ee69580c", + "url": "https://files.pythonhosted.org/packages/58/dd/3253f207f0d7ce5fe4b78d76c70e1e9433c4fc94f40044ac4105ed6c6301/simplejson-4.1.2-cp311-cp311-musllinux_1_2_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "7ce252b28fddbdd83db5bd7d93dad2a8a591d7ada098afec9c1b23d6b722a7a4", - "url": "https://files.pythonhosted.org/packages/80/7e/c9e6c0c4ad8415e64dad0c47f619b556b02680a41631b4dbc281d55dc54d/simplejson-4.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + "hash": "dbc4f989e44d6153b5097357d260336d8021c21b3ae9d8954c9daf55788bfc16", + "url": "https://files.pythonhosted.org/packages/64/b6/82c2322d80345113a16451ecd7f2f487c380de0dbcfdbdefee7b99095cbf/simplejson-4.1.2-cp311-cp311-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "820c69a4710400e9b248d5670647d60be58824369282d3925e516b3ff1a7cd82", - "url": "https://files.pythonhosted.org/packages/86/1c/e4d0eab695be3eb21d0f46bce820752031f03e7113f9c80a9b3c73ee7157/simplejson-4.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "53b56770b5893d91b24f6ba985eb5bade5908971f62cb7f8e1ed50a9314601b2", + "url": "https://files.pythonhosted.org/packages/89/85/268d7abe6feb708c6ceb6651d28e8120d7d9ffb409e7aeb1f3acbe514e10/simplejson-4.1.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "a94ebaecdbaa80d9551a3ec6bf0c9302fc8b53ab6c1b2bfd498a1df4cb28158d", - "url": "https://files.pythonhosted.org/packages/9c/a0/abd4785f36c3400f1fbb21f517be39295a750a714f04b7ee175adf6ef580/simplejson-4.1.1-cp312-cp312-macosx_10_13_x86_64.whl" + "hash": "a769bce267ef4091b7ef380bcad1c474f4e66bfcfecb571e996215dcdd24df70", + "url": "https://files.pythonhosted.org/packages/8d/f9/69d2be0cbcdc1bd6052998b7d22cb3e7c80c9d6a371eb345cf079401fe41/simplejson-4.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" }, { "algorithm": "sha256", - "hash": "0662cfe0482c9796bd097213b27f006815bfdc9b671264c3c0b7fc0e72b71d00", - "url": "https://files.pythonhosted.org/packages/9f/b9/f830b648ae04601e6813306535d8e0a4c178d6453cec539b85dafdac80ed/simplejson-4.1.1-cp310-cp310-musllinux_1_2_ppc64le.whl" + "hash": "eaf2652770fc3415498cb7446bdb399624cc685df868d58e09d6722b63e937f3", + "url": "https://files.pythonhosted.org/packages/8f/3d/aa0c2337b17aeee27c24dc512f88db6093ffbe224d7107d6ef0d1a3f35da/simplejson-4.1.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" }, { "algorithm": "sha256", - "hash": "1778e09a6e4bb4ef304627915dc4a838569d9e6b737c787925b4e98244bbbc16", - "url": "https://files.pythonhosted.org/packages/aa/06/7a6482f336338dbdb6ca6d3099b2fdc1c74c47eea3c6511975751e9198df/simplejson-4.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "0be6cf935487b8d0bc97c528c89d0432f22e33ca1e1d4fea666d50d36b5afe4f", + "url": "https://files.pythonhosted.org/packages/9f/de/dc931f8621a3a6f58f3582e345f1a9e620f3d622f110be2a39e3343a488f/simplejson-4.1.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" }, { "algorithm": "sha256", - "hash": "67341c95c0a168ab4a6d1e807e50463f1c8da932c3286d81e201266c427061fa", - "url": "https://files.pythonhosted.org/packages/b8/78/fc060d2e3b13c6ec59288574b8efac64075e316b2afba4396a56b2422f78/simplejson-4.1.1-cp312-cp312-macosx_11_0_arm64.whl" + "hash": "b2162d7f5e2e9dc48c08af14d91481b9ffbb8d8420d7d1539209fa7f0ba8823f", + "url": "https://files.pythonhosted.org/packages/ad/9d/2b91d17c91638987dfe54bf3d2257370b235b66c1fe2fdb84e10767ac159/simplejson-4.1.2-cp310-cp310-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "de2ed102fff88dacf543699f53ee3a533cc11539a39baa176b7e09dd783069d6", - "url": "https://files.pythonhosted.org/packages/c2/08/9a690da9a766161c06c627d805362cf159f1abe480969372b2897649b955/simplejson-4.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl" + "hash": "3733bf9afd79291eb0744b5b01041356df1b1bc25175a72519eb548751b61aeb", + "url": "https://files.pythonhosted.org/packages/b7/46/cd6f49506d633f5207c868c9373db594d4636b0fd69a2ce3dea53a1a05ff/simplejson-4.1.2-cp312-cp312-macosx_10_13_universal2.whl" }, { "algorithm": "sha256", - "hash": "b75c7ef874dbb350f41827cdf3cee23f5257bdcb0df46d4c01b34badb62dcfe8", - "url": "https://files.pythonhosted.org/packages/c2/2d/7832ed91cf4900f86c783d589bfac53358abfccb278f1c8b55eec167b395/simplejson-4.1.1-cp310-cp310-macosx_11_0_arm64.whl" + "hash": "d0b62163144dbc0dfc78df632a64ada3ce2e0760b65ead0f42e7d9c69be6f16f", + "url": "https://files.pythonhosted.org/packages/bf/50/5a6059682c6980d5f2b039aaa643d4d9e7272fc18eacfc7be30d922d20ba/simplejson-4.1.2-cp310-cp310-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "67e43e7c0555e10de6d83e1408035652fad28c983516e38c4e3a9a748c9af129", - "url": "https://files.pythonhosted.org/packages/c9/43/039982e956b06c6b019d48bdf9d4ec06f298adf6136552ad1979b94be0fd/simplejson-4.1.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl" + "hash": "78a0ff56305feec5217639247dba9174d20d4fa6538885a29b9910aad44fd92d", + "url": "https://files.pythonhosted.org/packages/d5/70/ff9cce6cdd7b2271ccf25e700a38986fa8ccf601fba405db28150414a7fb/simplejson-4.1.2-cp312-cp312-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "82fee635d7b73ad801030b05a75fbd34a098da0c2ecf600667a03636d09e1e42", - "url": "https://files.pythonhosted.org/packages/c9/fd/6dffb4956563d48bbe46b91ff341adae34920e94008fd6b8d728072abfc7/simplejson-4.1.1-cp311-cp311-musllinux_1_2_ppc64le.whl" + "hash": "c41397ba7c5d0a4ce2f058e8ebb0bf80703b0ba1cd1df9616399c35dd1a7df37", + "url": "https://files.pythonhosted.org/packages/d7/24/a0d405be16e7cbac5d1dab9b7f40a5c8dd681b546811047a8f102e53e125/simplejson-4.1.2-cp310-cp310-macosx_10_9_x86_64.whl" }, { "algorithm": "sha256", - "hash": "68e62eda21192c5ea9bb92d571ca46a4477fef48762f50d433de2b4253051551", - "url": "https://files.pythonhosted.org/packages/de/d2/a509ee37763e79aec75d68f8521db1440306edeba3b8b4064ab4ee8bf1d9/simplejson-4.1.1-cp311-cp311-musllinux_1_2_x86_64.whl" + "hash": "95569ac177885494967c1445a0fcc220eaa1ae53b71e852eb0d8689b683ca6d0", + "url": "https://files.pythonhosted.org/packages/d9/3a/bf9ab4db6f3c5e689acf5e3665fd1100413aa85604fd88bef879b2869b6e/simplejson-4.1.2-cp310-cp310-macosx_10_9_universal2.whl" }, { "algorithm": "sha256", - "hash": "93bf6653420258372444de90194dab8de8ff13d74b5d4263a5fefbbe8b8d2060", - "url": "https://files.pythonhosted.org/packages/f1/f5/e3ad592d089922abce2c2ea377548953ac55ffcbe061d600f01b9db2e6b6/simplejson-4.1.1-cp310-cp310-musllinux_1_2_aarch64.whl" + "hash": "f2156497f031d5c0051a335216f7ff5441746a93fbab5932e47105da7ef24ab9", + "url": "https://files.pythonhosted.org/packages/e7/3d/39e7253427dd4c2ec38596b944e3d3a53926cab7b3c2d28c43ef1a34d6d3/simplejson-4.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "4c47c46e16c8ea9e4850061e6ed5aa2b9cd2074cb2274bfd9c138cba15ce7453", - "url": "https://files.pythonhosted.org/packages/f2/ae/2c272971c8a87e2539c54a98eb6ff037bee1e2e93943c3986cf7500a4f3a/simplejson-4.1.1-cp311-cp311-macosx_10_9_x86_64.whl" + "hash": "630160f22edb2b13e05e0fe13dd80c2a064374f212696d3ee472f9ee13ebf4ac", + "url": "https://files.pythonhosted.org/packages/ec/dd/1ca3b57840863954e1d402287f8481c88f4e84bdc1cd27f6a0f3a7097b69/simplejson-4.1.2-cp312-cp312-macosx_10_13_x86_64.whl" }, { "algorithm": "sha256", - "hash": "4484960512db9c8124bfa91e0d8a9f9c302338f1c5454e74c21d7d022df10f46", - "url": "https://files.pythonhosted.org/packages/fe/8a/d0c08f4b8934b64469a63d461a68a01d5cc32faf313400dda2bdc1075a29/simplejson-4.1.1-cp310-cp310-macosx_10_9_x86_64.whl" + "hash": "6ae4186f90362e9c03c80a1cd5062a20f3a11ac9d391f7ee0ef0701a0e2b7394", + "url": "https://files.pythonhosted.org/packages/f1/e3/1cc7dbf4deebc16e9dc42db37f473b5b612d021eb10e69974be308425171/simplejson-4.1.2.tar.gz" } ], "project_name": "simplejson", "requires_dists": [], "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=2.7", - "version": "4.1.1" + "version": "4.1.2" }, { "artifacts": [ @@ -5567,19 +5692,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "e7e6b0769c8f51ed59acab6e994b00621096cfb1c640a7509295987388fbaf65", - "url": "https://files.pythonhosted.org/packages/5e/f5/0c41cb68dcae6b7de4fac4188a3a9589e21fb31df21ea3a2e888db95e6c9/soupsieve-2.8.4-py3-none-any.whl" + "hash": "8089a26fd974ca7a1f30276d3d8492ab266ab15af581642dfe8aa162e0c1c823", + "url": "https://files.pythonhosted.org/packages/eb/dc/ad025c1ee131eba60c69f4dd5779b18fcf1e6b21a343e2162a84d5d133c7/soupsieve-2.9.2-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "e121fd02e975c695e4e9e8774a5ee35d74714b59307868dcc5319ad2d9e3328e", - "url": "https://files.pythonhosted.org/packages/47/2c/0a5f6f8ee0d5589e48c7640213ed5175d52cf540a06725b628cc1a45d6ce/soupsieve-2.8.4.tar.gz" + "hash": "4a55d8cf158a9c2e587fa4922f1bbb91d68ac829e2d6f25403a85747c71daf74", + "url": "https://files.pythonhosted.org/packages/69/99/a6ca3beb3ccacb41fb3321d8a60e5566f9e6467601ef8eba6a17e1b89778/soupsieve-2.9.2.tar.gz" } ], "project_name": "soupsieve", "requires_dists": [], - "requires_python": ">=3.9", - "version": "2.8.4" + "requires_python": ">=3.10", + "version": "2.9.2" }, { "artifacts": [ @@ -5857,21 +5982,21 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", - "url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl" + "hash": "65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147", + "url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", - "url": "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz" + "hash": "547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47", + "url": "https://files.pythonhosted.org/packages/a3/26/b09b8010994eccc3c09092e6b34058f36a460eea2d4c3e8b910c695975a0/typing_inspection-0.4.4.tar.gz" } ], "project_name": "typing-inspection", "requires_dists": [ - "typing-extensions>=4.12.0" + "typing-extensions>=4.15.0" ], - "requires_python": ">=3.9", - "version": "0.4.2" + "requires_python": ">=3.10", + "version": "0.4.4" }, { "artifacts": [ @@ -6243,31 +6368,31 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85", - "url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl" + "hash": "d5b73dba6158a595ec9370350e7f2637bcac8d6c5e4fde34f30fcffb6103a5e4", + "url": "https://files.pythonhosted.org/packages/c4/0e/57f6bb3024a597b2e8ec4aee710ffe62ddc95af2e2bb1ee7a7abdc22c68c/wcwidth-0.8.3-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "91fbef97204b96a3d4d421609b80340b760cf33e26da123ff243d76b1fda8dda", - "url": "https://files.pythonhosted.org/packages/34/74/c6428f875774288bec1396f5bfcbc2d925700a4dad61727fd5f2b12f249d/wcwidth-0.8.2.tar.gz" + "hash": "d128512515fbf4612e0ff21fd6380399210318b7b54a9af59dff8454cf9730eb", + "url": "https://files.pythonhosted.org/packages/36/57/ed58088fafdf4c55a0ad6bde846502567645424d7ebf325230b9237f4085/wcwidth-0.8.3.tar.gz" } ], "project_name": "wcwidth", "requires_dists": [], "requires_python": ">=3.8", - "version": "0.8.2" + "version": "0.8.3" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "e68ad87fda378191081965ab02a185391c26e4e926adec855c3b0286a8369d49", - "url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl" + "hash": "4addd1d38d6a7fbe0eda22d45f25a40d74c8b290f3a99c0ac3d4023cf21f2da2", + "url": "https://files.pythonhosted.org/packages/c1/71/370a65bc7726a1cbf478445c898c7affe907aa42e2e9e5bb38319db74115/webob-1.8.11-py2.py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "1c963a11f307bc3f624fbab9dde737701eae255f32981b7a5486a88db1767c2b", - "url": "https://files.pythonhosted.org/packages/58/f9/974eafebfd0bd442b8848899fe7d30675c93f750c313e1a6fe61acbde1e3/webob-1.8.10.tar.gz" + "hash": "aa8c27231070b135c025e567a9cd7eda03f4df71352ffaac740cb6a75f0f81a5", + "url": "https://files.pythonhosted.org/packages/e6/92/9329872e36be90e25ba616ac6e9ee8c1be4326a1ea3fdffcdabd0eb48efb/webob-1.8.11.tar.gz" } ], "project_name": "webob", @@ -6282,7 +6407,7 @@ "setuptools; extra == \"docs\"" ], "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7", - "version": "1.8.10" + "version": "1.8.11" }, { "artifacts": [ @@ -6340,13 +6465,13 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "212281cab4dff978f6cedd499cd893e1f620791ca6ff7107cf270781e587eced", - "url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl" + "hash": "3217dcc807155e45db462d7ef2431f5ddda0d7273b700d05a67b271ceb1287ab", + "url": "https://files.pythonhosted.org/packages/2e/29/69cfbb602cd91690c55d38ba9fe53e6a7e76a6fa647bf38f19c138d25449/wheel-0.48.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "cc72bd1009ba0cf63922e28f94d9d83b920aa2bb28f798a31d0691b02fa3c9b3", - "url": "https://files.pythonhosted.org/packages/39/62/75f18a0f03b4219c456652c7780e4d749b929eb605c098ce3a5b6b6bc081/wheel-0.47.0.tar.gz" + "hash": "94800765601e9171bf5d58d066e640662842bcedcbab982b2c90787a2c987322", + "url": "https://files.pythonhosted.org/packages/d0/20/50ed6bdf27dec98b568a8ae25dc599f35baa3d9709f9e83fd1edb56b9a90/wheel-0.48.0.tar.gz" } ], "project_name": "wheel", @@ -6354,139 +6479,139 @@ "packaging>=24.0" ], "requires_python": ">=3.9", - "version": "0.47.0" + "version": "0.48.0" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "5bad217350f19ce99ca5b5e71d406765ea86fe541628426772b657375ee1c048", - "url": "https://files.pythonhosted.org/packages/6e/d2/6317eb6d4554855bbf12d61857774af34747bf88a42c19bf306de67e2fa3/wrapt-2.2.2-py3-none-any.whl" + "hash": "d8c7ed08477429752b8c44991f40ad7838b18332a160698740a6bfbc10d998a2", + "url": "https://files.pythonhosted.org/packages/00/39/3daf9f47be208606586de4568ba6713db53ebc8fd7a575aea1fe57983b69/wrapt-2.3.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "4bccea5cdecffa9dd70e343741f0e41e0a16619313d04b72f78bb525162ebcd0", - "url": "https://files.pythonhosted.org/packages/01/df/2def7e99d1fe87eea413f95f671924cdddcb08823b1ffd212748dfa6d062/wrapt-2.2.2-cp311-cp311-musllinux_1_2_aarch64.whl" + "hash": "5ab559e1b2551d23d54db2a0001c6d73bad022a254639561c5f6c382a9d6c2fe", + "url": "https://files.pythonhosted.org/packages/00/b8/9182e4c618a847be0baccb68e4602b070d0fa22c782cf058f4bc66b32709/wrapt-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl" }, { "algorithm": "sha256", - "hash": "e5a5290e4bf2f332fc29ce72ffb9a2fff678aaac047e2e9f5f7165cd7792e099", - "url": "https://files.pythonhosted.org/packages/02/49/bc0086292d239575b4c08f4cf8a4079fa58abbad58ec23abf84833a283ed/wrapt-2.2.2-cp311-cp311-musllinux_1_2_x86_64.whl" + "hash": "3d1c2c1b808600d2ea808e6360910a60ed5f409a4011655e10f9164ba0a414a6", + "url": "https://files.pythonhosted.org/packages/0e/60/9bda34c3d7d182aa703fe35339ae0ed4c4dad5e5c587f93890143e1f87fb/wrapt-2.3.0-cp311-cp311-musllinux_1_2_riscv64.whl" }, { "algorithm": "sha256", - "hash": "6d1a6050405bf334be33bf66296f113563622972a34900ae6fa60fd283a1a900", - "url": "https://files.pythonhosted.org/packages/0b/43/894f132d857ed5a9904d937baf368badcbe5ea9e436e2f1930fe21c9f1f0/wrapt-2.2.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "e5301c35cf75655eb33498f2bd6ae8703ca19940e3167dc9cdf740c712a39c60", + "url": "https://files.pythonhosted.org/packages/12/1e/8eded8615d39e3ce81f626937a3a87b280a2a86239a2bf14a4b4bb345034/wrapt-2.3.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "656593bb3f5529f03d27af4136c4d7b11990e470bcbc6fefa5ef218695bece55", - "url": "https://files.pythonhosted.org/packages/23/1b/545eee1c18f3af4cf140bb5822b6ef81ebe569df0a63ac109973103a30a5/wrapt-2.2.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + "hash": "e2e692bc0d63f881cf7006730a56bd4e0c2fab5dc318466942805d692b166276", + "url": "https://files.pythonhosted.org/packages/1f/d6/c66b4ba4eda49257c84d5c2df26118280f09ca7905aee20d0064db778d13/wrapt-2.3.0-cp310-cp310-musllinux_1_2_riscv64.whl" }, { "algorithm": "sha256", - "hash": "f1a2ff355ece6a111ca7a20dc86df6659c9205d3fcee674ca34f2a2854fd4e73", - "url": "https://files.pythonhosted.org/packages/27/15/0c2d55168707465abfc41f33c0b23d792a5fa9b65c26983606940900a120/wrapt-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl" + "hash": "816877aa749253149f9ecfd2635d4d948ecfa338e1a0311d187b1acb1bb8a3eb", + "url": "https://files.pythonhosted.org/packages/23/41/c35940ea1c423f129ebe4361db853bc80d4def6326242e1206fa15bf94f4/wrapt-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "10adb01371408c6de504a6658b9886480f1a4919a83752748a387a504a21df79", - "url": "https://files.pythonhosted.org/packages/29/de/3c833e03725b477e9ea34028224dd21a48781830101e4e036f77e8b6b102/wrapt-2.2.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "5d221a6e6ddd302b8397433184e96b59f259f50024b854db1c411a881586b6b8", + "url": "https://files.pythonhosted.org/packages/28/7f/cfd9bc4b1f5e424eeea83d0493e43f3b1b02707ce8e50c47945873982bd5/wrapt-2.3.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" }, { "algorithm": "sha256", - "hash": "8417fd3c674d3c8023d080292d29301531a12daf8bd938dd419710dd2f464f2b", - "url": "https://files.pythonhosted.org/packages/2a/85/180b40628b23772692a0c76e8030114e1c0ae068470ed531919f0a5f2a4a/wrapt-2.2.2-cp312-cp312-macosx_10_13_x86_64.whl" + "hash": "681a2d0eefd721998f90642762b8e75c2159ec531b20ad5e437245ea7b06a107", + "url": "https://files.pythonhosted.org/packages/2b/b0/c1f5a970721f06b85c0cd5142e0ff8fe067708abd779b0c4f4be7d61d09f/wrapt-2.3.0.tar.gz" }, { "algorithm": "sha256", - "hash": "3442eee2a5798f9b451f1b2cd7518ce8b7e28a2a364696c414460a0e295c012a", - "url": "https://files.pythonhosted.org/packages/33/be/27edce350b24e3054d9d047f65f16d4c4d4c1f3f31c4278a1f8a95c723c8/wrapt-2.2.2-cp312-cp312-musllinux_1_2_aarch64.whl" + "hash": "418f54bb09d1762db02c7009b4051149893af3153a87f92d70356703c11eea02", + "url": "https://files.pythonhosted.org/packages/35/ea/a0af2d9da62897af2a055484920de05dade30d2ba2c0d65cbdea875d3d8b/wrapt-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "a2d78c363f97d8bd718ee40432c66395685e9e98528ccaa423c3355d1715a26d", - "url": "https://files.pythonhosted.org/packages/34/f3/de70937472dd3e8a4e6811192f9c6075efdffd4a2cd9b4596bf160f89668/wrapt-2.2.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + "hash": "0bb2797048db0956348cb3058c33bc4184614f13231389cfbccc16a5d32780a7", + "url": "https://files.pythonhosted.org/packages/40/31/5822ce37ca8820c2ed35a498c67c8b37960b9cee2ba437fd32849d0a234c/wrapt-2.3.0-cp310-cp310-macosx_10_9_x86_64.whl" }, { "algorithm": "sha256", - "hash": "dfb00cb7bb22099e2f64b7340fb96113639aa7260c0972af3797ace2297b936c", - "url": "https://files.pythonhosted.org/packages/44/a7/6f42a3d03e44dc612a5dcff324e7366075a7857f0be2d49a8cb8a68279b8/wrapt-2.2.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "d0077f3d65541925fa83002f967b22ad6550d24813ac64cb905f717194128d9c", + "url": "https://files.pythonhosted.org/packages/49/2c/bc508fee75eb2919ed69769800b09968e4aab16897f909a23f39c81e323f/wrapt-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "518b0c5e323511ec56a38894802ddd5e1222626484e68efe63f201854ad788e5", - "url": "https://files.pythonhosted.org/packages/45/04/aa5309beed5344b00220ae6b3b24055852192656194c27947bee1736306a/wrapt-2.2.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "9790ea25190a4e0fe4cdf4eeb868e9d75f8a024a70a5b6bf9c348a3a2b72e731", + "url": "https://files.pythonhosted.org/packages/4d/e5/04f34d38e66d857dfc2fc4088d60e70c0e422467822defa49b2b4a26e17b/wrapt-2.3.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "2e096c9d39a59b35b63c9aacfbbbec2088ff51ff1fc31051acc60a07f42f273a", - "url": "https://files.pythonhosted.org/packages/5f/b3/7e6e9fcf4fe7e1b69a49fe6cc5a44e8224bab6283c5233c97e132f14908e/wrapt-2.2.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + "hash": "0a45ffae742ce91a16e11cb6c7cd71e7f9994f3cbd283b962ab093f5c6dcf525", + "url": "https://files.pythonhosted.org/packages/5b/4a/d17a0fad1bf1c5f2c887ff71fef75654141b0880bff71d157d955b5bec3a/wrapt-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl" }, { "algorithm": "sha256", - "hash": "55b9a899e6fff5444f229d30aa6e9ac92d2216d9d60f33c771b5d76a760d5f8e", - "url": "https://files.pythonhosted.org/packages/7d/b5/5c0b093eb48f8a062ef6267d3cb36e9bb1b88440181f6545a383c60efdf8/wrapt-2.2.2-cp311-cp311-macosx_11_0_arm64.whl" + "hash": "fc82c2ccc8e234c844f5303d9f2984b346dcdd53e94823ce8420d2c75b4b9023", + "url": "https://files.pythonhosted.org/packages/6c/21/1f780bba935dcf697c0c59de9be3a559bbb8e31a53ca3f25422023738432/wrapt-2.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "4402f57c5f0d0579599858ffbdd9bf4e3f0972f51096f2bd6cc7dab6b76ee49e", - "url": "https://files.pythonhosted.org/packages/84/9b/12e23264d8f4735e8483262f95c5a6b03c3665fd2a84bdf99a45b6a2f4ec/wrapt-2.2.2-cp310-cp310-musllinux_1_2_aarch64.whl" + "hash": "69e477046f2237ef0bc6547544ee73008dc764ca26eff44f09e976d221b34d5d", + "url": "https://files.pythonhosted.org/packages/6e/55/51b92daaf6defb57f4dc56bdcce985400f75c6984a03ca5e78ccac717028/wrapt-2.3.0-cp312-cp312-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "8374eb6b1a58809211e84ff835a182bb17ab2807a5bfef23204c8cff38178a00", - "url": "https://files.pythonhosted.org/packages/94/dc/66c61aca927230c9cf97a3cb005c803971a1076ff9f7d61085d035c20085/wrapt-2.2.2-cp310-cp310-macosx_11_0_arm64.whl" + "hash": "fc648a335d7e01adb3640b25f02fd0ea05886cf04d0af7f4ee902bc7b5e466e8", + "url": "https://files.pythonhosted.org/packages/71/71/4cd2151a236f44a6e2dd4ed8011838d7ba0be3d656c8bafdfc65a2ed1917/wrapt-2.3.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" }, { "algorithm": "sha256", - "hash": "0e7070c7472582e31af3dfc2622b2381a0df7435110a9388ed8db5ffbce67efb", - "url": "https://files.pythonhosted.org/packages/94/f2/21c90f2a16689702e2aaff45795b11018dff2c9b1242bac10d225483f676/wrapt-2.2.2-cp312-cp312-macosx_11_0_arm64.whl" + "hash": "a6e19531ae33c508cea7d84a7edfda01fa86e51b8d1a93a77712c55e6e469152", + "url": "https://files.pythonhosted.org/packages/73/31/6c7799d7b6431fcd7e1b83245fb45258a2d2c3a2187fbaecb83572a72d7a/wrapt-2.3.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" }, { "algorithm": "sha256", - "hash": "d619e1eed9bd4f6ed9f24cd61971aa086fa86505289628d464bcf8a2c2e3f328", - "url": "https://files.pythonhosted.org/packages/a5/ec/40aed2330e7f02ecf74386ffcfef9ccb7108c6a430f15b6a252b663b1bed/wrapt-2.2.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "ce9f398f868d2b3b27aa2ea4de79645ef9077aeeac8dfc2814b0d542c6a2b87f", + "url": "https://files.pythonhosted.org/packages/7a/5a/3c6117938be98754578ab83f5a40d7d0ea2cd2c487dc5cd6027ee7228229/wrapt-2.3.0-cp310-cp310-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "3b686cfc008776a3952d6213cb296ed7f45d782a8453936406faa89eac0835ab", - "url": "https://files.pythonhosted.org/packages/bc/c2/aa6c0c2206803068c6859dabe01f8c84c43744da93d4c67b8946d21655ee/wrapt-2.2.2-cp312-cp312-musllinux_1_2_x86_64.whl" + "hash": "1598becd30f8f2777d18564064eb4f4dbe1ab0e05a8f09786d0ef505ac782bf3", + "url": "https://files.pythonhosted.org/packages/7e/dd/63cd4c864c65ef4906df64bd2d378f4a62b54f28063f282dfb3bf93caead/wrapt-2.3.0-cp312-cp312-musllinux_1_2_riscv64.whl" }, { "algorithm": "sha256", - "hash": "e7f10ee0bd53673bfd52b67cbce83336fe6cad90d2377b03baf66491d2bbfb91", - "url": "https://files.pythonhosted.org/packages/bf/55/4d76175aaa97523c38f1d28f79d18ab41a1b116814158a818bc0eba00571/wrapt-2.2.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + "hash": "bff9a671bc00709cab5a7f745c592b5671873449db0ee2a569af994f16b29a4d", + "url": "https://files.pythonhosted.org/packages/84/ca/613cefd9c5977366b1587e61c0b428176d382e6d75b454084c5e58503042/wrapt-2.3.0-cp311-cp311-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "209112cafd963710a05d199aae431d79a28bc76eb8e6d1bbbb8ad24340722cae", - "url": "https://files.pythonhosted.org/packages/c7/f6/a906d01a2ce12157bad2404957b3e2140da354b8a70b2fa48bbf282871c0/wrapt-2.2.2-cp311-cp311-musllinux_1_2_riscv64.whl" + "hash": "ad71df7a04dd3497e9302e81f4a7c91bd401ea0e15a9df9029527900f94bee43", + "url": "https://files.pythonhosted.org/packages/a5/0f/94ae724c5087eb6054c0d63febd7094947dcf302fe058e2e0488102a872b/wrapt-2.3.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" }, { "algorithm": "sha256", - "hash": "3a4eb7964ff4643d333c84f880bcf554652b2a1050aebc54ae696327f61acfaf", - "url": "https://files.pythonhosted.org/packages/d6/a3/bcd5ec37289dcd85ecd4d15395a6a6063d60bc45ff94a9d77814e1e54d64/wrapt-2.2.2-cp310-cp310-musllinux_1_2_riscv64.whl" + "hash": "c8388ba7faf5dbf9ee106bb70d66f257629b1bd98091123e19e8a4553a319199", + "url": "https://files.pythonhosted.org/packages/c0/f2/1a3b949c0322fb27396eafd1044328c1cb0400e0b32105d75a3cd03096e7/wrapt-2.3.0-cp310-cp310-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "055e6fcfaa28e58c6a8c247d48b92be9d56f818b7068aa4f22b15b3343a09931", - "url": "https://files.pythonhosted.org/packages/e1/8b/59781d0fe7b0adfbea37f600857de4be68921e454aeecf1a11bda35cdccc/wrapt-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl" + "hash": "3da470536bf9645143323dd41b32db55c6f4304ad382094c1a1da8a92061e10d", + "url": "https://files.pythonhosted.org/packages/ca/ee/82f1fc9e431b5c2c5a6d201aa865dbeae3984c311c6d11a185f0c8367cf6/wrapt-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "6c99012a22f735a85eed7c4b86a3e99c30fdd57d9e115b2b45f796264b58d0bf", - "url": "https://files.pythonhosted.org/packages/e2/c4/9fd9679af8bf38e146652c7f47b6b352c3e5795b4ad1c0b7f94e15ac2aa7/wrapt-2.2.2-cp312-cp312-musllinux_1_2_riscv64.whl" + "hash": "392158c9a7f2ab1b8699418bfc0fe6f83548788c418b27d7bf2019ad3405cebb", + "url": "https://files.pythonhosted.org/packages/cb/89/ff7814f6eb6856b479946117d1138a2fbb46cdb6b1f379db359056c69743/wrapt-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" }, { "algorithm": "sha256", - "hash": "e542b7c5af91e2123a8aabf19894319d5ec4268d2a9ffd2f239386133fc47746", - "url": "https://files.pythonhosted.org/packages/f2/be/716d708f607fa70f8a6eb47dff8ee945d5278dfc89ffeeff33039d052e63/wrapt-2.2.2-cp310-cp310-musllinux_1_2_x86_64.whl" + "hash": "df4ce31150bcd5d9f36f816aac3010ab4f4bf8672ac1d3b0ac7d539ec61c7c02", + "url": "https://files.pythonhosted.org/packages/ce/17/42d670dbfafd49076c6eb2b7d67633d7e1c968e39bfb11a135acb6fac67b/wrapt-2.3.0-cp310-cp310-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "0788e321027c999bf221b667bd4a54aaefd1a36283749a860ac3eb77daed0302", - "url": "https://files.pythonhosted.org/packages/fe/a4/282c8e64300a59fc834518a54bf0afabb4ff9218b5fa76958b450459a844/wrapt-2.2.2.tar.gz" + "hash": "5ba1e5e08ddc46130e9682b2c249f2d1dd39bda9106ed4bd401b7519f18f41bd", + "url": "https://files.pythonhosted.org/packages/e8/ba/60bfd9b1a751f4fcb2d603668fc272d651ccdd339a56acf8c40ad21a0293/wrapt-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl" } ], "project_name": "wrapt", @@ -6495,7 +6620,7 @@ "setuptools; extra == \"dev\"" ], "requires_python": ">=3.9", - "version": "2.2.2" + "version": "2.3.0" }, { "artifacts": [ @@ -6615,6 +6740,125 @@ "requires_python": ">=3.10", "version": "4.1.0" }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "5e755153ac4faf64c10a4b6dd3307680166a3edf65b38df22df592610f8fa874", + "url": "https://files.pythonhosted.org/packages/9e/33/848922889e946d4befc415c219fe516af75c49555d8e736e183bfd30db42/zope_event-6.2-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "b97d5d6327067ee6b9dfcbdf606ade9ade70991e19c162e808ea39e5fcf0f8d3", + "url": "https://files.pythonhosted.org/packages/93/41/faa10af34d48d9cd6fa0249a1162943ad84a9590bd1a06939981e6640416/zope_event-6.2.tar.gz" + } + ], + "project_name": "zope-event", + "requires_dists": [ + "Sphinx; extra == \"docs\"", + "zope.testrunner>=6.4; extra == \"test\"" + ], + "requires_python": ">=3.10", + "version": "6.2" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "28b68c24131545c1d13fd2178bbd065e67f09db885d8426adf1fbdf2b6b66372", + "url": "https://files.pythonhosted.org/packages/05/89/7767a6f9b0bb41a4d3777e8f93bfeb1b9a23ea643f83ce96163d9d672c8b/zope_interface-8.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "6246f7a4b196bd054469f4fd4ffdac307974061f0d2b1ef4da87ddff13a7f885", + "url": "https://files.pythonhosted.org/packages/00/9c/53361a3cbf7ae2529d69a252547b129afa44f75d7019a76b15cecad44c91/zope_interface-8.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "42fb95008784a3b50c4b79e4488845d1950c57eef17ebc9c53a680084fb93da2", + "url": "https://files.pythonhosted.org/packages/11/56/4cf64b40123af62ed9dad3d689df853d9ff8f431ae06408e087061a9b87a/zope_interface-8.6-cp310-cp310-macosx_10_9_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "a38b221cc649a2daacaff9d629a2ba9c4a8967669d253f9a6a597f46d46732f0", + "url": "https://files.pythonhosted.org/packages/17/4f/41bde1796fa8cbb32f50facd261dd4124daa850c29666270e85e2bb8e91a/zope_interface-8.6-cp312-cp312-macosx_11_0_arm64.whl" + }, + { + "algorithm": "sha256", + "hash": "826f99c38f4bfcf7165885a0c59f03c6c25e0df8cdb0544f882cda61616fe845", + "url": "https://files.pythonhosted.org/packages/21/00/27467685e40d5ee01f542c8b0b33682b07af363419f4c64cbb61b8bf48d5/zope_interface-8.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "b40ef9b4873afb5d0dec02b8d2dfde1cf18c72337b60c99cb735961e0bac05c0", + "url": "https://files.pythonhosted.org/packages/26/39/a8481b926e42c44a6fcc670904f8251469ec42edbff1ba066719ca1e7fb4/zope_interface-8.6.tar.gz" + }, + { + "algorithm": "sha256", + "hash": "6df4bd16923d247c34e12dc394dab20d99d96aa2e15a6b163c2dda1dd582fff6", + "url": "https://files.pythonhosted.org/packages/2e/02/c82afe287924ddcbc78fd2f4646f16e3ba9d03bf3f5e1ea4bedce711de3c/zope_interface-8.6-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "a43e669d68fd8c10fe315812f7e1d262c6c00e9667f29f799a3771f9a3b5b41d", + "url": "https://files.pythonhosted.org/packages/41/7d/d3abda21695ee441f2278f226b4b22ecb604cf0d96efb3d39507415abdcb/zope_interface-8.6-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "3e0383361da2793ea332e2d12b753a32ac57b3b89c8c3a9c6dd04374ae142c0f", + "url": "https://files.pythonhosted.org/packages/65/7a/80fa8eb011bf78b72438a0ea0f672efe97ac5c9e9ff07d3304143ef5d611/zope_interface-8.6-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl" + }, + { + "algorithm": "sha256", + "hash": "919510e0d470c189cb84164b953f81e8a513aa2593fdc9e4982340838cd1099b", + "url": "https://files.pythonhosted.org/packages/85/55/3092a23c3bdbcc9402ad74e69dae3fa49cc9f12bceef35079c98449bc60e/zope_interface-8.6-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl" + }, + { + "algorithm": "sha256", + "hash": "a2c5963a26e1fe47bdb3494ba2aa91904c7898873af400dc3bdcaa808a57783a", + "url": "https://files.pythonhosted.org/packages/90/b8/59d9a455a73cae715eacca70003d943e8a8413b196454bb49530c16769bd/zope_interface-8.6-cp310-cp310-macosx_11_0_arm64.whl" + }, + { + "algorithm": "sha256", + "hash": "780a66db884c0e2b0e6b34b4900f86916945a7c03d3be40ec845b051fcc052cd", + "url": "https://files.pythonhosted.org/packages/98/e1/b2d78ecb8aec59114111ed8c25894c0421afecc5e89b36fc356e2b07a607/zope_interface-8.6-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl" + }, + { + "algorithm": "sha256", + "hash": "ebb513c9e47702525897148e38271f7b6bf12c61bd084cdddfd0e03b542f8100", + "url": "https://files.pythonhosted.org/packages/a2/9b/60a71a998fd819a7b9ed24c3544f862280f222828f421561e28885dcecc5/zope_interface-8.6-cp311-cp311-macosx_11_0_arm64.whl" + }, + { + "algorithm": "sha256", + "hash": "192bb756a8f62395b4fe47cbb853c171f20389d5226fbfa97128bb2f76abad8d", + "url": "https://files.pythonhosted.org/packages/be/0a/33bcf5c825c749205c832e82d14224ff38011d20dd9dbf7a0ffe51a589ae/zope_interface-8.6-cp312-cp312-macosx_10_9_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "9217b1123f6aeec9ddf1789bffd83da3123546d551c164a99f862a5d1f5ac0f8", + "url": "https://files.pythonhosted.org/packages/dc/5a/126eeee4da016f5cca4db2297496069d5f1ba901fb53ebf104f9c087a113/zope_interface-8.6-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "dd25d6da3b3c8216080a0eefb3c01719913782690427fb9ba2ddad98ed8970f4", + "url": "https://files.pythonhosted.org/packages/df/b0/5715b7635e5e25dd26ae32453e784cab59401078aeb3e401027675068583/zope_interface-8.6-cp311-cp311-macosx_10_9_x86_64.whl" + } + ], + "project_name": "zope-interface", + "requires_dists": [ + "Sphinx; extra == \"docs\"", + "coverage[toml]; extra == \"test\"", + "coverage[toml]; extra == \"testing\"", + "furo; extra == \"docs\"", + "repoze.sphinx.autointerface; extra == \"docs\"", + "zope.event; extra == \"test\"", + "zope.event; extra == \"testing\"", + "zope.testing; extra == \"test\"", + "zope.testing; extra == \"testing\"" + ], + "requires_python": ">=3.10", + "version": "8.6" + }, { "artifacts": [ { @@ -6865,6 +7109,7 @@ "editor", "eventlet>=0.40.3", "flask", + "gevent", "gitdb", "gitpython", "graphviz", diff --git a/requirements-pants.txt b/requirements-pants.txt index 2f70614609..2cb21b10f3 100644 --- a/requirements-pants.txt +++ b/requirements-pants.txt @@ -19,7 +19,8 @@ openapi-spec-validator # gitpython & gitdb are used for pack management gitdb gitpython -# st2common/tests/integration/test_util_green.py requires greenlet (as does eventlet) +# st2common/tests/integration/test_util_green.py requires greenlet (as does eventlet and gevent) +gevent greenlet # Gunicorn dropped eventlet support as of v26. https://gunicorn.org/news/#2600-2026-05-05 gunicorn<26 diff --git a/requirements.txt b/requirements.txt index 4098f5e754..c718839869 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,76 +7,77 @@ # update the component requirements.txt RandomWords amqp==5.3.1 -apscheduler==3.11.0 -argcomplete==3.6.2 +apscheduler==3.11.3 +argcomplete==3.7.2 backports.zoneinfo[tzdata]; python_version<"3.9" bcrypt==5.0.0 -cffi==1.17.1 -chardet==5.2.0 +cffi==2.1.1 +chardet==7.6.0 ciso8601 -cryptography==43.0.3 -decorator==5.2.1 +cryptography>=41.0.5,<46 +decorator==5.3.1 dnspython -editor==1.6.6 -eventlet==0.40.3 +editor==1.8.0 +eventlet==0.41.2 +gevent==26.8.0 gitdb==4.0.12 -gitpython==3.1.45 -greenlet==3.1.1 -gunicorn<26 +gitpython==3.1.61 +greenlet==3.5.5 +gunicorn==25.3.0 importlib-metadata importlib_resources==6.5.2 jinja2==3.1.6 jsonpath-rw==1.4.0 jsonschema==4.26.0 -kombu==5.5.4 +kombu==5.6.2 lockfile==0.12.2 mock==5.2.0 -mongoengine==0.29.1 -networkx==3.1 -openapi-spec-validator==0.7.2 -orjson==3.10.15 +mongoengine==0.29.3 +networkx==3.3 +openapi-spec-validator==0.9.0 +orjson==3.12.0 orquesta@ git+https://github.com/StackStorm/orquesta.git oslo.config==9.6.0 oslo.utils==7.3.0 paramiko==3.5.1 -prettytable==3.11.0 -prompt-toolkit==3.0.52 -psutil==7.1.0 +prettytable==3.18.0 +prompt-toolkit==3.0.53 +psutil==7.2.2 pyOpenSSL<25.2 -pygments==2.19.2 +pygments==2.21.0 pymongo==4.6.3 -pynacl==1.6.0 -pyparsing==3.1.4 +pynacl==1.6.2 +pyparsing==3.3.2 pyrabbit pysocks pytest==7.0.1 python-dateutil==2.9.0.post0 python-json-logger python-statsd==2.1.0 -pytz==2025.2 +pytz==2026.3.post1 pywinrm==0.5.0 pyyaml==6.0.3 -redis==6.1.1 +redis==8.1.0 referencing -requests==2.32.4 +requests==2.34.2 retrying==1.4.2 routes==2.5.1 semver==3.0.4 setuptools==82.0.1 simplejson six==1.17.0 -sseclient-py==1.8.0 +sseclient-py==1.9.0 st2-auth-backend-flat-file st2-auth-backend-pam@ git+https://github.com/StackStorm/st2-auth-backend-pam.git@master st2-auth-ldap@ git+https://github.com/StackStorm/st2-auth-ldap.git@master st2-rbac-backend@ git+https://github.com/StackStorm/st2-rbac-backend.git@master -stevedore==5.3.0 -tenacity==9.0.0 -tooz==6.3.0 +stevedore==5.8.0 +tenacity==9.1.4 +tooz==8.1.0 typing-extensions>=4.13.2; python_version < "3.11" -urllib3==2.2.3 -webob==1.8.9 -webtest==3.0.1 +urllib3==2.7.0 +webob==1.8.11 +webtest==3.0.7 zake==0.2.2 -zipp==3.20.2 -zstandard==0.23.0 +zipp==4.1.0 +zstandard==0.25.0 diff --git a/st2actions/in-requirements.txt b/st2actions/in-requirements.txt index 7a1b952619..6ad4aa4333 100644 --- a/st2actions/in-requirements.txt +++ b/st2actions/in-requirements.txt @@ -2,6 +2,7 @@ apscheduler python-dateutil eventlet +gevent jinja2 kombu oslo.config diff --git a/st2actions/requirements.txt b/st2actions/requirements.txt index afd851908b..897ac8b488 100644 --- a/st2actions/requirements.txt +++ b/st2actions/requirements.txt @@ -5,21 +5,22 @@ # If you want to update depdencies for a single component, modify the # in-requirements.txt for that component and then run 'make requirements' to # update the component requirements.txt -apscheduler==3.11.0 +apscheduler==3.11.3 backports.zoneinfo[tzdata]; python_version<"3.9" -chardet==5.2.0 -eventlet==0.40.3 -gitpython==3.1.45 +chardet==7.6.0 +eventlet==0.41.2 +gevent==26.8.0 +gitpython==3.1.61 jinja2==3.1.6 -kombu==5.5.4 +kombu==5.6.2 lockfile==0.12.2 oslo.config==9.6.0 oslo.utils==7.3.0 -pyparsing==3.1.4 +pyparsing==3.3.2 python-dateutil==2.9.0.post0 python-json-logger pyyaml==6.0.3 -requests==2.32.4 +requests==2.34.2 setuptools==82.0.1 six==1.17.0 -urllib3==2.2.3 +urllib3==2.7.0 diff --git a/st2actions/st2actions/cmd/actionrunner.py b/st2actions/st2actions/cmd/actionrunner.py index 05f48f6464..fad4b52cb1 100644 --- a/st2actions/st2actions/cmd/actionrunner.py +++ b/st2actions/st2actions/cmd/actionrunner.py @@ -31,6 +31,7 @@ from st2common.service_setup import setup as common_setup from st2common.service_setup import teardown as common_teardown from st2common.service_setup import deregister_service +from st2common.util import concurrency __all__ = ["main"] @@ -41,7 +42,10 @@ def _setup_sigterm_handler(action_worker): def sigterm_handler(signum=None, frame=None): # This will cause SystemExit to be throw and allow for component cleanup. - action_worker.kill() + # action_worker.kill() blocks waiting for the greenlet to die, which gevent + # forbids doing directly inside a signal callback (BlockingSwitchOutError), + # so defer it to a freshly spawned greenlet instead. + concurrency.spawn(action_worker.kill) # Register a SIGTERM signal handler which calls sys.exit which causes SystemExit to # be thrown. We catch SystemExit and handle cleanup there. diff --git a/st2actions/st2actions/cmd/scheduler.py b/st2actions/st2actions/cmd/scheduler.py index a2a0487237..f4d9fe6a65 100644 --- a/st2actions/st2actions/cmd/scheduler.py +++ b/st2actions/st2actions/cmd/scheduler.py @@ -29,6 +29,7 @@ from st2common.service_setup import teardown as common_teardown from st2common.service_setup import setup as common_setup from st2common.service_setup import deregister_service +from st2common.util import concurrency __all__ = ["main"] @@ -101,8 +102,6 @@ def _run_scheduler(): # Wait on both handler and entrypoint. If either fails, we want to shut down gracefully. # Poll the threads to detect when any of them fails - import eventlet - threads_to_monitor = [ (handler._main_thread, "handler_main"), (handler._cleanup_thread, "handler_cleanup"), @@ -125,7 +124,7 @@ def _run_scheduler(): # failure. for thread, name in dead_threads: try: - thread.wait() # Raises if the thread raised. + concurrency.wait(thread) # Raises if the thread raised. except Exception as e: LOG.error("Thread %s failed: %s", name, e) # Re-raise to let outer exception handler deal with shutdown @@ -138,7 +137,7 @@ def _run_scheduler(): return 0 # Sleep briefly to avoid tight loop and allow other greenlets to run - eventlet.sleep(0.1) + concurrency.sleep(0.1) except Exception as e: # If we caught an exception, it's already been logged and components shut down # Re-raise it so tests and monitoring can detect the failure diff --git a/st2actions/st2actions/cmd/workflow_engine.py b/st2actions/st2actions/cmd/workflow_engine.py index 45ab4286f7..127c4410e1 100644 --- a/st2actions/st2actions/cmd/workflow_engine.py +++ b/st2actions/st2actions/cmd/workflow_engine.py @@ -33,6 +33,7 @@ from st2common.service_setup import setup as common_setup from st2common.service_setup import teardown as common_teardown from st2common.service_setup import deregister_service +from st2common.util import concurrency __all__ = ["main"] @@ -42,7 +43,10 @@ def setup_sigterm_handler(engine): def sigterm_handler(signum=None, frame=None): # This will cause SystemExit to be throw and allow for component cleanup. - engine.kill() + # engine.kill() blocks waiting for the greenlet to die, which gevent forbids + # doing directly inside a signal callback (BlockingSwitchOutError), so defer + # it to a freshly spawned greenlet instead. + concurrency.spawn(engine.kill) # Register a SIGTERM signal handler which calls sys.exit which causes SystemExit to # be thrown. We catch SystemExit and handle cleanup there. diff --git a/st2actions/st2actions/policies/retry.py b/st2actions/st2actions/policies/retry.py index 225952875d..6fc546a738 100644 --- a/st2actions/st2actions/policies/retry.py +++ b/st2actions/st2actions/policies/retry.py @@ -17,9 +17,8 @@ import functools -import eventlet - from st2common import log as logging +from st2common.util import concurrency from st2common.models.db.liveaction import LiveActionDB import st2common.services.action as action_services from st2common.constants.action import LIVEACTION_STATUS_FAILED @@ -103,7 +102,7 @@ def apply_after(self, target): # status if self.delay > 0: re_run_live_action = functools.partial( - eventlet.spawn_after, + concurrency.spawn_after, self.delay, self._re_run_live_action, live_action_db=live_action_db, @@ -111,7 +110,7 @@ def apply_after(self, target): else: # Even if delay is 0, use a small delay (0.1 seconds) to prevent busy wait re_run_live_action = functools.partial( - eventlet.spawn_after, + concurrency.spawn_after, 0.1, self._re_run_live_action, live_action_db=live_action_db, diff --git a/st2actions/st2actions/scheduler/handler.py b/st2actions/st2actions/scheduler/handler.py index 59cd730edc..27d6d43633 100644 --- a/st2actions/st2actions/scheduler/handler.py +++ b/st2actions/st2actions/scheduler/handler.py @@ -15,7 +15,6 @@ from __future__ import absolute_import -import eventlet import retrying from oslo_config import cfg @@ -35,6 +34,7 @@ from st2common.persistence.liveaction import LiveAction from st2common.persistence.execution_queue import ActionExecutionSchedulingQueue from st2common.util import action_db as action_utils +from st2common.util import concurrency from st2common.metrics import base as metrics from st2common.exceptions import db as db_exc @@ -53,7 +53,9 @@ class ActionExecutionSchedulingQueueHandler(object): def __init__(self): self.message_type = LiveActionDB self._shutdown = False - self._pool = eventlet.GreenPool(size=cfg.CONF.scheduler.pool_size) + self._pool = concurrency.get_green_pool_class()( + size=cfg.CONF.scheduler.pool_size + ) # If an ActionExecutionSchedulingQueueItemDB object hasn't been updated fore more than # this amount of milliseconds, it will be marked as "handled=False". # As soon as an item is picked by scheduler to be processed, it should be processed very @@ -71,7 +73,7 @@ def run(self): LOG.debug("Starting scheduler handler...") while not self._shutdown: - eventlet.greenthread.sleep(cfg.CONF.scheduler.sleep_interval) + concurrency.sleep(cfg.CONF.scheduler.sleep_interval) self.process() @retrying.retry( @@ -83,13 +85,15 @@ def process(self): execution_queue_item_db = self._get_next_execution() if execution_queue_item_db: - self._pool.spawn(self._handle_execution, execution_queue_item_db) + concurrency.pool_spawn( + self._pool, self._handle_execution, execution_queue_item_db + ) def cleanup(self): LOG.debug("Starting scheduler garbage collection...") while not self._shutdown: - eventlet.greenthread.sleep(cfg.CONF.scheduler.gc_interval) + concurrency.sleep(cfg.CONF.scheduler.gc_interval) self._handle_garbage_collection() def _reset_handling_flag(self): @@ -565,14 +569,14 @@ def start(self): self._shutdown = False # Spawn the worker threads. - self._main_thread = eventlet.spawn(self.run) - self._cleanup_thread = eventlet.spawn(self.cleanup) + self._main_thread = concurrency.spawn(self.run) + self._cleanup_thread = concurrency.spawn(self.cleanup) # Link the threads to the shutdown function. If either of the threads exited with error, # then initiate shutdown which will allow the waits below to throw exception to the # main process. - self._main_thread.link(self.shutdown) - self._cleanup_thread.link(self.shutdown) + concurrency.link(self._main_thread, self.shutdown) + concurrency.link(self._cleanup_thread, self.shutdown) def shutdown(self, *args, **kwargs): if not self._shutdown: @@ -581,7 +585,7 @@ def shutdown(self, *args, **kwargs): def wait(self): # Wait for the worker threads to complete. If there is an exception thrown in the thread, # then the exception will be propagated to the main process for a proper return code. - self._main_thread.wait() or self._cleanup_thread.wait() + concurrency.wait(self._main_thread) or concurrency.wait(self._cleanup_thread) def get_handler(): diff --git a/st2actions/st2actions/workflows/workflows.py b/st2actions/st2actions/workflows/workflows.py index 6672069e6f..ebf24cf3ef 100644 --- a/st2actions/st2actions/workflows/workflows.py +++ b/st2actions/st2actions/workflows/workflows.py @@ -19,8 +19,6 @@ from orquesta import statuses from tooz.coordination import GroupNotCreated from st2common.services import coordination -from eventlet.semaphore import Semaphore -from eventlet import spawn_after from st2common.constants import action as ac_const from st2common import log as logging from st2common.metrics import base as metrics @@ -55,7 +53,7 @@ class WorkflowExecutionHandler(consumers.VariableMessageHandler): def __init__(self, connection, queues): super(WorkflowExecutionHandler, self).__init__(connection, queues) self._active_messages = 0 - self._semaphore = Semaphore() + self._semaphore = concurrency.Semaphore() # This is required to ensure workflows stuck in pausing state after shutdown transition to paused state after engine startup. self._delay = 30 @@ -107,7 +105,9 @@ def process(self, message): self._active_messages -= 1 def start(self, wait): - spawn_after(self._delay, self._resume_workflows_paused_during_shutdown) + concurrency.spawn_after( + self._delay, self._resume_workflows_paused_during_shutdown + ) super(WorkflowExecutionHandler, self).start(wait=wait) def shutdown(self): diff --git a/st2actions/tests/integration/test_actions_queue_consumer.py b/st2actions/tests/integration/test_actions_queue_consumer.py index aa37b5e589..1832020262 100644 --- a/st2actions/tests/integration/test_actions_queue_consumer.py +++ b/st2actions/tests/integration/test_actions_queue_consumer.py @@ -15,10 +15,11 @@ from __future__ import absolute_import import random -import eventlet from unittest import TestCase +from st2common.util import concurrency + from st2common.transport.consumers import ActionsQueueConsumer from st2common.transport.kombu import Exchange, Queue from st2common.transport.publishers import PoolPublisher @@ -44,25 +45,25 @@ def test_stop_consumption_on_shutdown(self): watcher = ActionsQueueConsumer( connection=connection, queues=queue, handler=self ) - watcher_thread = eventlet.greenthread.spawn(watcher.run) + watcher_thread = concurrency.spawn(watcher.run) # Give it some time to start up since we are publishing on a new queue - eventlet.sleep(0.5) + concurrency.sleep(0.5) body = LiveActionDB( status="scheduled", action="core.local", action_is_workflow=False ) publisher.publish(payload=body, exchange=exchange) - eventlet.sleep(0.2) + concurrency.sleep(0.2) self.assertEqual(self.message_count, 1) body = LiveActionDB( status="scheduled", action="core.local", action_is_workflow=True ) watcher.shutdown() - eventlet.sleep(1) + concurrency.sleep(1) publisher.publish(payload=body, exchange=exchange) # Second published message won't be consumed. self.assertEqual(self.message_count, 1) - watcher_thread.kill() + concurrency.kill(watcher_thread) def process(self, liveaction): self.message_count = self.message_count + 1 diff --git a/st2actions/tests/unit/policies/test_concurrency.py b/st2actions/tests/unit/policies/test_concurrency.py index 57647b238a..221ca80f58 100644 --- a/st2actions/tests/unit/policies/test_concurrency.py +++ b/st2actions/tests/unit/policies/test_concurrency.py @@ -21,7 +21,7 @@ # This import must be early for import-time side-effects. # Importing st2actions.scheduler relies on config being parsed :/ -from st2tests import DbTestCase, EventletTestCase, ExecutionDbTestCase +from st2tests import DbTestCase, GreenThreadTestCase, ExecutionDbTestCase import st2common from st2actions.scheduler import handler as scheduling_queue @@ -78,10 +78,10 @@ mock.MagicMock(side_effect=MockExecutionPublisher.publish_update), ) @mock.patch.object(CUDPublisher, "publish_create", mock.MagicMock(return_value=None)) -class ConcurrencyPolicyTestCase(EventletTestCase, ExecutionDbTestCase): +class ConcurrencyPolicyTestCase(GreenThreadTestCase, ExecutionDbTestCase): @classmethod def setUpClass(cls): - EventletTestCase.setUpClass() + GreenThreadTestCase.setUpClass() DbTestCase.setUpClass() # Override the coordinator to use the noop driver otherwise the tests will be blocked. diff --git a/st2actions/tests/unit/policies/test_concurrency_by_attr.py b/st2actions/tests/unit/policies/test_concurrency_by_attr.py index cdccbb2e22..7fb9050896 100644 --- a/st2actions/tests/unit/policies/test_concurrency_by_attr.py +++ b/st2actions/tests/unit/policies/test_concurrency_by_attr.py @@ -20,7 +20,7 @@ # This import must be early for import-time side-effects. # Importing st2actions.scheduler relies on config being parsed :/ -from st2tests import ExecutionDbTestCase, EventletTestCase +from st2tests import ExecutionDbTestCase, GreenThreadTestCase import st2common from st2actions.scheduler import handler as scheduling_queue @@ -76,10 +76,10 @@ mock.MagicMock(side_effect=MockExecutionPublisher.publish_update), ) @mock.patch.object(CUDPublisher, "publish_create", mock.MagicMock(return_value=None)) -class ConcurrencyByAttributePolicyTestCase(EventletTestCase, ExecutionDbTestCase): +class ConcurrencyByAttributePolicyTestCase(GreenThreadTestCase, ExecutionDbTestCase): @classmethod def setUpClass(cls): - EventletTestCase.setUpClass() + GreenThreadTestCase.setUpClass() ExecutionDbTestCase.setUpClass() # Override the coordinator to use the noop driver otherwise the tests will be blocked. diff --git a/st2actions/tests/unit/test_scheduler.py b/st2actions/tests/unit/test_scheduler.py index 65a59bd869..2b9c00a2fe 100644 --- a/st2actions/tests/unit/test_scheduler.py +++ b/st2actions/tests/unit/test_scheduler.py @@ -17,7 +17,8 @@ import datetime import mock -import eventlet + +from st2common.util import concurrency import st2common from st2tests import ExecutionDbTestCase @@ -147,7 +148,7 @@ def test_next_execution(self): ) # Wait maximum delay seconds so the query works as expected - eventlet.sleep(1.0) + concurrency.sleep(1.0) for index in expected_order: test_case = test_cases[index] diff --git a/st2actions/tests/unit/test_scheduler_entrypoint.py b/st2actions/tests/unit/test_scheduler_entrypoint.py index 7aa101a702..fcccf37866 100644 --- a/st2actions/tests/unit/test_scheduler_entrypoint.py +++ b/st2actions/tests/unit/test_scheduler_entrypoint.py @@ -13,9 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -import eventlet import mock +from st2common.util import concurrency + from st2actions.cmd.scheduler import _run_scheduler from st2actions.scheduler.handler import ActionExecutionSchedulingQueueHandler from st2actions.scheduler.entrypoint import SchedulerEntrypoint @@ -26,20 +27,20 @@ def mock_handler_run(self): - # NOTE: We use eventlet.sleep to emulate async nature of this process - eventlet.sleep(0.2) + # NOTE: We use concurrency.sleep to emulate async nature of this process + concurrency.sleep(0.2) raise Exception("handler run exception") def mock_handler_cleanup(self): - # NOTE: We use eventlet.sleep to emulate async nature of this process - eventlet.sleep(0.2) + # NOTE: We use concurrency.sleep to emulate async nature of this process + concurrency.sleep(0.2) raise Exception("handler clean exception") def mock_entrypoint_start(self): - # NOTE: We use eventlet.sleep to emulate async nature of this process - eventlet.sleep(0.2) + # NOTE: We use concurrency.sleep to emulate async nature of this process + concurrency.sleep(0.2) raise Exception("entrypoint start exception") @@ -47,11 +48,11 @@ class SchedulerServiceEntryPointTestCase(CleanDbTestCase): @mock.patch.object(ActionExecutionSchedulingQueueHandler, "run", mock_handler_run) @mock.patch("st2actions.cmd.scheduler.LOG") def test_service_exits_correctly_on_fatal_exception_in_handler_run(self, mock_log): - run_thread = eventlet.spawn(_run_scheduler) + run_thread = concurrency.spawn(_run_scheduler) # The scheduler now raises exceptions instead of returning 1 with self.assertRaises(Exception) as cm: - run_thread.wait() + concurrency.wait(run_thread) self.assertIn("handler run exception", str(cm.exception)) @@ -65,11 +66,11 @@ def test_service_exits_correctly_on_fatal_exception_in_handler_run(self, mock_lo def test_service_exits_correctly_on_fatal_exception_in_handler_cleanup( self, mock_log ): - run_thread = eventlet.spawn(_run_scheduler) + run_thread = concurrency.spawn(_run_scheduler) # The scheduler now raises exceptions instead of returning 1 with self.assertRaises(Exception) as cm: - run_thread.wait() + concurrency.wait(run_thread) self.assertIn("handler clean exception", str(cm.exception)) @@ -81,11 +82,11 @@ def test_service_exits_correctly_on_fatal_exception_in_handler_cleanup( def test_service_exits_correctly_on_fatal_exception_in_entrypoint_start( self, mock_log ): - run_thread = eventlet.spawn(_run_scheduler) + run_thread = concurrency.spawn(_run_scheduler) # The scheduler now raises exceptions instead of returning 1 with self.assertRaises(Exception) as cm: - run_thread.wait() + concurrency.wait(run_thread) self.assertIn("entrypoint start exception", str(cm.exception)) diff --git a/st2actions/tests/unit/test_scheduler_retry.py b/st2actions/tests/unit/test_scheduler_retry.py index d975964bc6..26aed121d8 100644 --- a/st2actions/tests/unit/test_scheduler_retry.py +++ b/st2actions/tests/unit/test_scheduler_retry.py @@ -16,8 +16,9 @@ # This import must be first for import-time side-effects. from st2tests.base import CleanDbTestCase -import eventlet import mock + +from st2common.util import concurrency import pymongo import uuid @@ -25,7 +26,6 @@ from st2common.models.db import execution_queue as ex_q_db from st2common.persistence import execution_queue as ex_q_db_access - __all__ = ["SchedulerHandlerRetryTestCase"] @@ -42,38 +42,44 @@ class SchedulerHandlerRetryTestCase(CleanDbTestCase): side_effect=[pymongo.errors.ConnectionFailure(), MOCK_QUEUE_ITEM] ), ) - @mock.patch.object(eventlet.GreenPool, "spawn", mock.MagicMock(return_value=None)) + @mock.patch.object( + concurrency.get_green_pool_class(), "spawn", mock.MagicMock(return_value=None) + ) def test_handler_retry_connection_error(self): scheduling_queue_handler = handler.ActionExecutionSchedulingQueueHandler() scheduling_queue_handler.process() # Make sure retry occurs and that _handle_execution in process is called. calls = [mock.call(scheduling_queue_handler._handle_execution, MOCK_QUEUE_ITEM)] - eventlet.GreenPool.spawn.assert_has_calls(calls) + concurrency.get_green_pool_class().spawn.assert_has_calls(calls) @mock.patch.object( handler.ActionExecutionSchedulingQueueHandler, "_get_next_execution", mock.MagicMock(side_effect=[pymongo.errors.ConnectionFailure()] * 3), ) - @mock.patch.object(eventlet.GreenPool, "spawn", mock.MagicMock(return_value=None)) + @mock.patch.object( + concurrency.get_green_pool_class(), "spawn", mock.MagicMock(return_value=None) + ) def test_handler_retries_exhausted(self): scheduling_queue_handler = handler.ActionExecutionSchedulingQueueHandler() self.assertRaises( pymongo.errors.ConnectionFailure, scheduling_queue_handler.process ) - self.assertEqual(eventlet.GreenPool.spawn.call_count, 0) + self.assertEqual(concurrency.get_green_pool_class().spawn.call_count, 0) @mock.patch.object( handler.ActionExecutionSchedulingQueueHandler, "_get_next_execution", mock.MagicMock(side_effect=KeyError()), ) - @mock.patch.object(eventlet.GreenPool, "spawn", mock.MagicMock(return_value=None)) + @mock.patch.object( + concurrency.get_green_pool_class(), "spawn", mock.MagicMock(return_value=None) + ) def test_handler_retry_unexpected_error(self): scheduling_queue_handler = handler.ActionExecutionSchedulingQueueHandler() self.assertRaises(KeyError, scheduling_queue_handler.process) - self.assertEqual(eventlet.GreenPool.spawn.call_count, 0) + self.assertEqual(concurrency.get_green_pool_class().spawn.call_count, 0) @mock.patch.object( ex_q_db_access.ActionExecutionSchedulingQueue, diff --git a/st2actions/tests/unit/test_scheduler_shutdown_on_rabbitmq_failure.py b/st2actions/tests/unit/test_scheduler_shutdown_on_rabbitmq_failure.py index 0ed3a84296..8bee20562b 100644 --- a/st2actions/tests/unit/test_scheduler_shutdown_on_rabbitmq_failure.py +++ b/st2actions/tests/unit/test_scheduler_shutdown_on_rabbitmq_failure.py @@ -20,10 +20,10 @@ from __future__ import absolute_import -import eventlet import mock from kombu import exceptions as kombu_exceptions +from st2common.util import concurrency from st2tests.base import DbTestCase import st2tests.config as tests_config from st2actions.cmd import scheduler @@ -49,14 +49,14 @@ def test_scheduler_shuts_down_when_entrypoint_consumer_fails( """ Test that when the entrypoint consumer thread fails with KombuError after exhausting retry attempts, the scheduler: - 1. Detects the failure via eventlet.wait_all() + 1. Detects the failure via concurrency.wait() 2. Calls shutdown() on both handler and entrypoint 3. Re-raises the exception to exit the process """ # Create mock handler with threads that would run forever mock_handler = mock.MagicMock() - mock_handler_main_thread = eventlet.spawn(lambda: eventlet.sleep(1000)) - mock_handler_cleanup_thread = eventlet.spawn(lambda: eventlet.sleep(1000)) + mock_handler_main_thread = concurrency.spawn(lambda: concurrency.sleep(1000)) + mock_handler_cleanup_thread = concurrency.spawn(lambda: concurrency.sleep(1000)) mock_handler._main_thread = mock_handler_main_thread mock_handler._cleanup_thread = mock_handler_cleanup_thread mock_get_handler.return_value = mock_handler @@ -68,7 +68,7 @@ def test_scheduler_shuts_down_when_entrypoint_consumer_fails( def failing_consumer(): raise kombu_exceptions.OperationalError("[Errno 111] ECONNREFUSED") - mock_entrypoint_consumer_thread = eventlet.spawn(failing_consumer) + mock_entrypoint_consumer_thread = concurrency.spawn(failing_consumer) mock_entrypoint._consumer_thread = mock_entrypoint_consumer_thread mock_get_entrypoint.return_value = mock_entrypoint @@ -98,15 +98,17 @@ def test_scheduler_shuts_down_when_handler_main_thread_fails( def failing_main_thread(): raise RuntimeError("Handler main thread failed") - mock_handler_main_thread = eventlet.spawn(failing_main_thread) - mock_handler_cleanup_thread = eventlet.spawn(lambda: eventlet.sleep(1000)) + mock_handler_main_thread = concurrency.spawn(failing_main_thread) + mock_handler_cleanup_thread = concurrency.spawn(lambda: concurrency.sleep(1000)) mock_handler._main_thread = mock_handler_main_thread mock_handler._cleanup_thread = mock_handler_cleanup_thread mock_get_handler.return_value = mock_handler # Create mock entrypoint that would run forever mock_entrypoint = mock.MagicMock() - mock_entrypoint_consumer_thread = eventlet.spawn(lambda: eventlet.sleep(1000)) + mock_entrypoint_consumer_thread = concurrency.spawn( + lambda: concurrency.sleep(1000) + ) mock_entrypoint._consumer_thread = mock_entrypoint_consumer_thread mock_get_entrypoint.return_value = mock_entrypoint @@ -132,19 +134,21 @@ def test_scheduler_shuts_down_when_handler_cleanup_thread_fails( """ # Create mock handler with cleanup thread that fails mock_handler = mock.MagicMock() - mock_handler_main_thread = eventlet.spawn(lambda: eventlet.sleep(1000)) + mock_handler_main_thread = concurrency.spawn(lambda: concurrency.sleep(1000)) def failing_cleanup_thread(): raise RuntimeError("Handler cleanup thread failed") - mock_handler_cleanup_thread = eventlet.spawn(failing_cleanup_thread) + mock_handler_cleanup_thread = concurrency.spawn(failing_cleanup_thread) mock_handler._main_thread = mock_handler_main_thread mock_handler._cleanup_thread = mock_handler_cleanup_thread mock_get_handler.return_value = mock_handler # Create mock entrypoint that would run forever mock_entrypoint = mock.MagicMock() - mock_entrypoint_consumer_thread = eventlet.spawn(lambda: eventlet.sleep(1000)) + mock_entrypoint_consumer_thread = concurrency.spawn( + lambda: concurrency.sleep(1000) + ) mock_entrypoint._consumer_thread = mock_entrypoint_consumer_thread mock_get_entrypoint.return_value = mock_entrypoint @@ -170,8 +174,8 @@ def test_scheduler_connection_error_propagates( """ # Create mock handler with threads that would run forever mock_handler = mock.MagicMock() - mock_handler_main_thread = eventlet.spawn(lambda: eventlet.sleep(1000)) - mock_handler_cleanup_thread = eventlet.spawn(lambda: eventlet.sleep(1000)) + mock_handler_main_thread = concurrency.spawn(lambda: concurrency.sleep(1000)) + mock_handler_cleanup_thread = concurrency.spawn(lambda: concurrency.sleep(1000)) mock_handler._main_thread = mock_handler_main_thread mock_handler._cleanup_thread = mock_handler_cleanup_thread mock_get_handler.return_value = mock_handler @@ -182,7 +186,7 @@ def test_scheduler_connection_error_propagates( def failing_consumer(): raise kombu_exceptions.ConnectionError("Connection lost") - mock_entrypoint_consumer_thread = eventlet.spawn(failing_consumer) + mock_entrypoint_consumer_thread = concurrency.spawn(failing_consumer) mock_entrypoint._consumer_thread = mock_entrypoint_consumer_thread mock_get_entrypoint.return_value = mock_entrypoint diff --git a/st2actions/tests/unit/test_worker.py b/st2actions/tests/unit/test_worker.py index 271d225a25..c4b0ba6ae1 100644 --- a/st2actions/tests/unit/test_worker.py +++ b/st2actions/tests/unit/test_worker.py @@ -16,8 +16,9 @@ from __future__ import absolute_import from bson.errors import InvalidStringData -import eventlet import mock + +from st2common.util import concurrency import os from oslo_config import cfg from tooz.drivers.redis import RedisDriver @@ -168,11 +169,11 @@ def test_worker_shutdown(self): ) liveaction_db = LiveAction.add_or_update(liveaction_db) executions.create_execution_object(liveaction_db) - runner_thread = eventlet.spawn(action_worker._run_action, liveaction_db) + runner_thread = concurrency.spawn(action_worker._run_action, liveaction_db) # Wait for the worker up to 10s to add the liveaction to _running_liveactions. for i in range(0, int(10 / 0.1)): - eventlet.sleep(0.1) + concurrency.sleep(0.1) if len(action_worker._running_liveactions) > 0: break @@ -196,7 +197,7 @@ def test_worker_shutdown(self): # Wait for the local runner to complete. This will activate the finally block in # _run_action but will not result in KeyError because the discard method is used to # to remove the liveaction from _running_liveactions. - runner_thread.wait() + concurrency.wait(runner_thread) @mock.patch.object( RedisDriver, @@ -231,25 +232,25 @@ def test_worker_graceful_shutdown_with_multiple_runners(self): ) liveaction_db = LiveAction.add_or_update(liveaction_db) executions.create_execution_object(liveaction_db) - runner_thread = eventlet.spawn(action_worker._run_action, liveaction_db) + runner_thread = concurrency.spawn(action_worker._run_action, liveaction_db) # Wait for the worker up to 10s to add the liveaction to _running_liveactions. for i in range(0, int(10 / 0.1)): - eventlet.sleep(0.1) + concurrency.sleep(0.1) if len(action_worker._running_liveactions) > 0: break self.assertEqual(len(action_worker._running_liveactions), 1) # Shutdown the worker to trigger the abandon process. - shutdown_thread = eventlet.spawn(action_worker.shutdown) + shutdown_thread = concurrency.spawn(action_worker.shutdown) # Make sure the temporary file has been deleted. self.assertFalse(os.path.isfile(temp_file)) # Wait for the worker up to 10s to remove the liveaction from _running_liveactions. for i in range(0, int(10 / 0.1)): - eventlet.sleep(0.1) + concurrency.sleep(0.1) if len(action_worker._running_liveactions) < 1: break liveaction_db = LiveAction.get_by_id(liveaction_db.id) @@ -265,8 +266,8 @@ def test_worker_graceful_shutdown_with_multiple_runners(self): # Wait for the local runner to complete. This will activate the finally block in # _run_action but will not result in KeyError because the discard method is used to # to remove the liveaction from _running_liveactions. - runner_thread.wait() - shutdown_thread.kill() + concurrency.wait(runner_thread) + concurrency.kill(shutdown_thread) def test_worker_graceful_shutdown_with_single_runner(self): self.reset_config( @@ -297,24 +298,24 @@ def test_worker_graceful_shutdown_with_single_runner(self): ) liveaction_db = LiveAction.add_or_update(liveaction_db) executions.create_execution_object(liveaction_db) - runner_thread = eventlet.spawn(action_worker._run_action, liveaction_db) + runner_thread = concurrency.spawn(action_worker._run_action, liveaction_db) # Wait for the worker up to 3s to add the liveaction to _running_liveactions. for i in range(0, int(3 / 0.05)): - eventlet.sleep(0.05) + concurrency.sleep(0.05) if len(action_worker._running_liveactions) > 0: break self.assertEqual(len(action_worker._running_liveactions), 1) # Shutdown the worker to trigger the abandon process. - shutdown_thread = eventlet.spawn(action_worker.shutdown) + shutdown_thread = concurrency.spawn(action_worker.shutdown) # Wait for action runner shutdown sequence to complete - eventlet.sleep(0.5) + concurrency.sleep(0.5) # Wait for the worker up to 3s to remove the liveaction from _running_liveactions. for i in range(0, int(3 / 0.05)): - eventlet.sleep(0.05) + concurrency.sleep(0.05) if len(action_worker._running_liveactions) < 1: break liveaction_db = LiveAction.get_by_id(liveaction_db.id) @@ -336,8 +337,8 @@ def test_worker_graceful_shutdown_with_single_runner(self): # Wait for the local runner to complete. This will activate the finally block in # _run_action but will not result in KeyError because the discard method is used to # to remove the liveaction from _running_liveactions. - runner_thread.wait() - shutdown_thread.kill() + concurrency.wait(runner_thread) + concurrency.kill(shutdown_thread) @mock.patch.object( RedisDriver, @@ -370,26 +371,26 @@ def test_worker_graceful_shutdown_exit_timeout(self): ) liveaction_db = LiveAction.add_or_update(liveaction_db) executions.create_execution_object(liveaction_db) - runner_thread = eventlet.spawn(action_worker._run_action, liveaction_db) + runner_thread = concurrency.spawn(action_worker._run_action, liveaction_db) # Wait for the worker up to 10s to add the liveaction to _running_liveactions. for i in range(0, int(10 / 0.1)): - eventlet.sleep(0.1) + concurrency.sleep(0.1) if len(action_worker._running_liveactions) > 0: break self.assertEqual(len(action_worker._running_liveactions), 1) # Shutdown the worker to trigger the abandon process. - shutdown_thread = eventlet.spawn(action_worker.shutdown) + shutdown_thread = concurrency.spawn(action_worker.shutdown) # Continue the execution for 2+ seconds to ensure timeout occurs. # The action sleeps for 5 seconds, so it will still be running # when the 2 second timeout expires. - eventlet.sleep(3) + concurrency.sleep(3) # Wait for the worker up to 10s to remove the liveaction from _running_liveactions. for i in range(0, int(10 / 0.1)): - eventlet.sleep(0.1) + concurrency.sleep(0.1) if len(action_worker._running_liveactions) < 1: break liveaction_db = LiveAction.get_by_id(liveaction_db.id) @@ -411,5 +412,5 @@ def test_worker_graceful_shutdown_exit_timeout(self): # Wait for the local runner to complete. This will activate the finally block in # _run_action but will not result in KeyError because the discard method is used to # to remove the liveaction from _running_liveactions. - runner_thread.wait() - shutdown_thread.kill() + concurrency.wait(runner_thread) + concurrency.kill(shutdown_thread) diff --git a/st2actions/tests/unit/test_workflow_engine.py b/st2actions/tests/unit/test_workflow_engine.py index ed6440bd57..2f4344a4c4 100644 --- a/st2actions/tests/unit/test_workflow_engine.py +++ b/st2actions/tests/unit/test_workflow_engine.py @@ -15,9 +15,10 @@ from __future__ import absolute_import -import eventlet import mock +from st2common.util import concurrency + # This import must be early for import-time side-effects. import st2tests @@ -290,7 +291,7 @@ def test_process_error_handling_has_error(self, mock_get_lock): self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_RUNNING) # Sleep up to the test config gc_max_idle_sec before running gc. - eventlet.sleep(cfg.CONF.workflow_engine.gc_max_idle_sec) + concurrency.sleep(cfg.CONF.workflow_engine.gc_max_idle_sec) # Run garbage collection. gc = garbage_collector.GarbageCollectorService() @@ -320,10 +321,10 @@ def test_workflow_engine_shutdown(self): )[0] self.assertEqual(wf_ex_db.status, action_constants.LIVEACTION_STATUS_RUNNING) workflow_engine = workflows.get_engine() - eventlet.spawn(workflow_engine.shutdown) + concurrency.spawn(workflow_engine.shutdown) # Sleep for few seconds to ensure execution transitions to pausing. - eventlet.sleep(8) + concurrency.sleep(8) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_PAUSING) @@ -349,7 +350,7 @@ def test_workflow_engine_shutdown(self): workflow_engine = workflows.get_engine() workflow_engine._delay = 0 workflow_engine.start(False) - eventlet.sleep(workflow_engine._delay + 5) + concurrency.sleep(workflow_engine._delay + 5) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertTrue( lv_ac_db.status @@ -383,10 +384,10 @@ def test_workflow_engine_shutdown_with_multiple_members(self): self.assertEqual(wf_ex_db.status, action_constants.LIVEACTION_STATUS_RUNNING) workflow_engine = workflows.get_engine() - eventlet.spawn(workflow_engine.shutdown) + concurrency.spawn(workflow_engine.shutdown) # Sleep for few seconds to ensure shutdown sequence completes. - eventlet.sleep(5) + concurrency.sleep(5) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_RUNNING) @@ -425,10 +426,10 @@ def test_workflow_engine_shutdown_with_service_registry_disabled(self): self.assertEqual(wf_ex_db.status, action_constants.LIVEACTION_STATUS_RUNNING) workflow_engine = workflows.get_engine() - eventlet.spawn(workflow_engine.shutdown) + concurrency.spawn(workflow_engine.shutdown) # Sleep for few seconds to ensure shutdown sequence completes. - eventlet.sleep(5) + concurrency.sleep(5) # WFE doesn't pause the workflow, since service registry is disabled. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) @@ -457,11 +458,11 @@ def test_workflow_engine_shutdown_first_then_start(self): workflow_engine._delay = 5 # Initiate shutdown first - eventlet.spawn(workflow_engine.shutdown) - eventlet.spawn_after(1, workflow_engine.start, True) + concurrency.spawn(workflow_engine.shutdown) + concurrency.spawn_after(1, workflow_engine.start, True) # Sleep for few seconds to ensure shutdown sequence completes. - eventlet.sleep(2) + concurrency.sleep(2) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) # Shutdown routine acquires the lock first @@ -476,7 +477,7 @@ def test_workflow_engine_shutdown_first_then_start(self): workflows.get_engine().process(t1_ac_ex_db) # Startup sequence won't proceed until shutdown routine completes. # Assuming shutdown sequence is complete, start up sequence will resume the workflow. - eventlet.sleep(workflow_engine._delay + 5) + concurrency.sleep(workflow_engine._delay + 5) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertTrue( lv_ac_db.status @@ -514,12 +515,12 @@ def test_workflow_engine_start_first_then_shutdown(self): workflow_engine._delay = 0 # Initiate start first - eventlet.spawn(workflow_engine.start, True) - eventlet.spawn_after(1, workflow_engine.shutdown) + concurrency.spawn(workflow_engine.start, True) + concurrency.spawn_after(1, workflow_engine.shutdown) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) # Startup routine acquires the lock first and shutdown routine sees a new member present in registry. - eventlet.sleep(workflow_engine._delay + 5) + concurrency.sleep(workflow_engine._delay + 5) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_RUNNING) diff --git a/st2api/in-requirements.txt b/st2api/in-requirements.txt index 25c9369f60..f2f6d5cdb3 100644 --- a/st2api/in-requirements.txt +++ b/st2api/in-requirements.txt @@ -1,5 +1,6 @@ # Remember to list implicit packages here, otherwise version won't be fixated! eventlet +gevent jsonschema kombu mongoengine diff --git a/st2api/requirements.txt b/st2api/requirements.txt index 0a4d53eeb2..0942a0d280 100644 --- a/st2api/requirements.txt +++ b/st2api/requirements.txt @@ -6,14 +6,15 @@ # in-requirements.txt for that component and then run 'make requirements' to # update the component requirements.txt backports.zoneinfo[tzdata]; python_version<"3.9" -eventlet==0.40.3 -gunicorn<26 +eventlet==0.41.2 +gevent==26.8.0 +gunicorn==25.3.0 jsonschema==4.26.0 -kombu==5.5.4 -mongoengine==0.29.1 +kombu==5.6.2 +mongoengine==0.29.3 oslo.config==9.6.0 oslo.utils==7.3.0 pymongo==4.6.3 -pyparsing==3.1.4 +pyparsing==3.3.2 simplejson six==1.17.0 diff --git a/st2api/st2api/cmd/api.py b/st2api/st2api/cmd/api.py index b80f6f4bed..1b640e0347 100644 --- a/st2api/st2api/cmd/api.py +++ b/st2api/st2api/cmd/api.py @@ -1,4 +1,4 @@ -# Copyright 2020 The StackStorm Authors. +# Copyright 2020-2026 The StackStorm Authors. # Copyright 2019 Extreme Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,9 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os -import sys - # NOTE: It's important that we perform monkey patch as early as possible before any other modules # are important, otherwise SSL support for MongoDB won't work. # See https://github.com/StackStorm/st2/issues/4832 and https://github.com/gevent/gevent/issues/1016 @@ -24,9 +21,11 @@ monkey_patch() -import eventlet +import os +import sys + from oslo_config import cfg -from eventlet import wsgi +from st2common.util import concurrency from st2common import log as logging from st2common.service_setup import setup as common_setup @@ -79,11 +78,11 @@ def _run_server(): LOG.info("(PID=%s) ST2 API is serving on http://%s:%s.", os.getpid(), host, port) - max_pool_size = eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS - worker_pool = eventlet.GreenPool(max_pool_size) - sock = eventlet.listen((host, port)) + max_pool_size = concurrency.get_default_green_pool_size() + worker_pool = concurrency.get_green_pool_class()(max_pool_size) + sock = concurrency.listen_server(host, port) - wsgi.server( + concurrency.wsgi_server( sock, app.setup_app(), custom_pool=worker_pool, log=LOG, log_output=False ) return 0 diff --git a/st2api/tests/integration/test_gunicorn_configs.py b/st2api/tests/integration/test_gunicorn_configs.py index c7df6d3978..77bf1e55ca 100644 --- a/st2api/tests/integration/test_gunicorn_configs.py +++ b/st2api/tests/integration/test_gunicorn_configs.py @@ -18,37 +18,43 @@ from six.moves import http_client import requests -import eventlet -from eventlet.green import subprocess import pytest +from st2common.util import concurrency + import st2tests.config from st2common.models.utils import profiling from st2common.util.shell import kill_process from st2tests.base import IntegrationTestCase - BASE_DIR = os.path.dirname(os.path.abspath(__file__)) ST2_CONFIG_PATH = os.path.join(BASE_DIR, "../../../conf/st2.tests.conf") +# Gunicorn's worker class must match the concurrency library the spawned process will +# use (per ST2_CONFIG_PATH above), or the WSGI worker hangs: eventlet/gevent monkey +# patching under the other library's gunicorn worker doesn't work. +GUNICORN_WORKER_CLASS = concurrency._get_concurrency_library_from_conf(ST2_CONFIG_PATH) + class GunicornWSGIEntryPointTestCase(IntegrationTestCase): @pytest.mark.skipif(profiling.is_enabled(), reason="Profiling is enabled") def test_st2api_wsgi_entry_point(self): port = random.randint(10000, 30000) - cmd = ( - 'gunicorn st2api.wsgi:application -k eventlet -b "127.0.0.1:%s" --workers 1' - % port + cmd = 'gunicorn st2api.wsgi:application -k %s -b "127.0.0.1:%s" --workers 1' % ( + GUNICORN_WORKER_CLASS, + port, ) env = os.environ.copy() env["ST2_CONFIG_PATH"] = ST2_CONFIG_PATH env.update(st2tests.config.db_opts_as_env_vars()) env.update(st2tests.config.mq_opts_as_env_vars()) env.update(st2tests.config.coord_opts_as_env_vars()) - process = subprocess.Popen(cmd, env=env, shell=True, preexec_fn=os.setsid) + process = concurrency.subprocess_popen( + cmd, env=env, shell=True, preexec_fn=os.setsid + ) try: self.add_process(process=process) - eventlet.sleep(8) + concurrency.sleep(8) self.assertProcessIsRunning(process=process) response = requests.get("http://127.0.0.1:%s/v1/actions" % (port)) self.assertEqual(response.status_code, http_client.OK) @@ -59,18 +65,20 @@ def test_st2api_wsgi_entry_point(self): def test_st2auth(self): port = random.randint(10000, 30000) cmd = ( - 'gunicorn st2auth.wsgi:application -k eventlet -b "127.0.0.1:%s" --workers 1' - % port + 'gunicorn st2auth.wsgi:application -k %s -b "127.0.0.1:%s" --workers 1' + % (GUNICORN_WORKER_CLASS, port) ) env = os.environ.copy() env["ST2_CONFIG_PATH"] = ST2_CONFIG_PATH env.update(st2tests.config.db_opts_as_env_vars()) env.update(st2tests.config.mq_opts_as_env_vars()) env.update(st2tests.config.coord_opts_as_env_vars()) - process = subprocess.Popen(cmd, env=env, shell=True, preexec_fn=os.setsid) + process = concurrency.subprocess_popen( + cmd, env=env, shell=True, preexec_fn=os.setsid + ) try: self.add_process(process=process) - eventlet.sleep(8) + concurrency.sleep(8) self.assertProcessIsRunning(process=process) response = requests.post("http://127.0.0.1:%s/tokens" % (port)) self.assertEqual(response.status_code, http_client.UNAUTHORIZED) diff --git a/st2auth/in-requirements.txt b/st2auth/in-requirements.txt index 94e873fe41..d635ec8ddf 100644 --- a/st2auth/in-requirements.txt +++ b/st2auth/in-requirements.txt @@ -1,6 +1,7 @@ # Remember to list implicit packages here, otherwise version won't be fixated! bcrypt eventlet +gevent oslo.config pymongo six diff --git a/st2auth/requirements.txt b/st2auth/requirements.txt index 20d6f58add..83789f05fb 100644 --- a/st2auth/requirements.txt +++ b/st2auth/requirements.txt @@ -6,12 +6,13 @@ # in-requirements.txt for that component and then run 'make requirements' to # update the component requirements.txt bcrypt==5.0.0 -eventlet==0.40.3 -gunicorn<26 +eventlet==0.41.2 +gevent==26.8.0 +gunicorn==25.3.0 oslo.config==9.6.0 pymongo==4.6.3 six==1.17.0 st2-auth-backend-flat-file st2-auth-backend-pam@ git+https://github.com/StackStorm/st2-auth-backend-pam.git@master st2-auth-ldap@ git+https://github.com/StackStorm/st2-auth-ldap.git@master -stevedore==5.3.0 +stevedore==5.8.0 diff --git a/st2auth/st2auth/cmd/api.py b/st2auth/st2auth/cmd/api.py index e817765d97..27554efb64 100644 --- a/st2auth/st2auth/cmd/api.py +++ b/st2auth/st2auth/cmd/api.py @@ -1,4 +1,4 @@ -# Copyright 2020 The StackStorm Authors. +# Copyright 2020-2026 The StackStorm Authors. # Copyright 2019 Extreme Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,17 +17,16 @@ monkey_patch() -import eventlet import os import sys from oslo_config import cfg -from eventlet import wsgi from st2common import log as logging from st2common.service_setup import setup as common_setup from st2common.service_setup import teardown as common_teardown from st2common.service_setup import deregister_service +from st2common.util import concurrency from st2auth import config config.register_opts(ignore_errors=True) @@ -75,29 +74,32 @@ def _run_server(): cert_file_path = os.path.realpath(cfg.CONF.auth.cert) key_file_path = os.path.realpath(cfg.CONF.auth.key) - if use_ssl and not os.path.isfile(cert_file_path): - raise ValueError('Certificate file "%s" doesn\'t exist' % (cert_file_path)) + socket = concurrency.listen(host, port) - if use_ssl and not os.path.isfile(key_file_path): - raise ValueError('Private key file "%s" doesn\'t exist' % (key_file_path)) + if use_ssl: + scheme = "https" + if not os.path.isfile(cert_file_path): + raise ValueError(f'Certificate file "{cert_file_path}" does not exist') - socket = eventlet.listen((host, port)) + if not os.path.isfile(key_file_path): + raise ValueError(f'Private key file "{key_file_path}" does not exist') - if use_ssl: - socket = eventlet.wrap_ssl( + socket = concurrency.wrap_ssl( socket, certfile=cert_file_path, keyfile=key_file_path, server_side=True ) + else: + scheme = "http" LOG.info('ST2 Auth API running in "%s" auth mode', cfg.CONF.auth.mode) LOG.info( "(PID=%s) ST2 Auth API is serving on %s://%s:%s.", os.getpid(), - "https" if use_ssl else "http", + scheme, host, port, ) - wsgi.server(socket, app.setup_app(), log=LOG, log_output=False) + concurrency.wsgi_server(socket, app.setup_app(), log=LOG, log_output=False) return 0 diff --git a/st2client/requirements.txt b/st2client/requirements.txt index 6d254bdd4f..c4344c2393 100644 --- a/st2client/requirements.txt +++ b/st2client/requirements.txt @@ -5,26 +5,26 @@ # If you want to update depdencies for a single component, modify the # in-requirements.txt for that component and then run 'make requirements' to # update the component requirements.txt -argcomplete==3.6.2 -cffi==1.17.1 -chardet==5.2.0 -cryptography==43.0.3 -editor==1.6.6 +argcomplete==3.7.2 +cffi==2.1.1 +chardet==7.6.0 +cryptography>=41.0.5,<46 +editor==1.8.0 importlib-metadata jsonpath-rw==1.4.0 jsonschema==4.26.0 -orjson==3.10.15 -prettytable==3.11.0 -prompt-toolkit==3.0.52 +orjson==3.12.0 +prettytable==3.18.0 +prompt-toolkit==3.0.53 pyOpenSSL<25.2 -pygments==2.19.2 +pygments==2.21.0 pysocks python-dateutil==2.9.0.post0 -pytz==2025.2 +pytz==2026.3.post1 pyyaml==6.0.3 -requests==2.32.4 +requests==2.34.2 six==1.17.0 -sseclient-py==1.8.0 +sseclient-py==1.9.0 typing-extensions>=4.13.2; python_version < "3.11" -urllib3==2.2.3 -zipp==3.20.2 +urllib3==2.7.0 +zipp==4.1.0 diff --git a/st2common/in-requirements.txt b/st2common/in-requirements.txt index 8ce1732fe6..e3da530e7c 100644 --- a/st2common/in-requirements.txt +++ b/st2common/in-requirements.txt @@ -3,6 +3,7 @@ apscheduler dnspython python-dateutil eventlet +gevent # used by eventlet greenlet jinja2 diff --git a/st2common/requirements.txt b/st2common/requirements.txt index 44201bfbeb..803ac5b7ba 100644 --- a/st2common/requirements.txt +++ b/st2common/requirements.txt @@ -6,47 +6,48 @@ # in-requirements.txt for that component and then run 'make requirements' to # update the component requirements.txt amqp==5.3.1 -apscheduler==3.11.0 +apscheduler==3.11.3 backports.zoneinfo[tzdata]; python_version<"3.9" -cffi==1.17.1 -chardet==5.2.0 +cffi==2.1.1 +chardet==7.6.0 ciso8601 -cryptography==43.0.3 -decorator==5.2.1 +cryptography>=41.0.5,<46 +decorator==5.3.1 dnspython -eventlet==0.40.3 +eventlet==0.41.2 +gevent==26.8.0 gitdb==4.0.12 -gitpython==3.1.45 -greenlet==3.1.1 +gitpython==3.1.61 +greenlet==3.5.5 importlib_resources==6.5.2 jinja2==3.1.6 jsonpath-rw==1.4.0 jsonschema==4.26.0 -kombu==5.5.4 +kombu==5.6.2 lockfile==0.12.2 -mongoengine==0.29.1 -networkx==3.1 -openapi-spec-validator==0.7.2 -orjson==3.10.15 +mongoengine==0.29.3 +networkx==3.3 +openapi-spec-validator==0.9.0 +orjson==3.12.0 orquesta@ git+https://github.com/StackStorm/orquesta.git oslo.config==9.6.0 paramiko==3.5.1 pyOpenSSL<25.2 pymongo==4.6.3 -pynacl==1.6.0 +pynacl==1.6.2 python-dateutil==2.9.0.post0 python-statsd==2.1.0 pyyaml==6.0.3 -redis==6.1.1 -requests==2.32.4 +redis==8.1.0 +requests==2.34.2 retrying==1.4.2 routes==2.5.1 semver==3.0.4 six==1.17.0 st2-rbac-backend@ git+https://github.com/StackStorm/st2-rbac-backend.git@master -tenacity==9.0.0 -tooz==6.3.0 -urllib3==2.2.3 -webob==1.8.9 +tenacity==9.1.4 +tooz==8.1.0 +urllib3==2.7.0 +webob==1.8.11 zake==0.2.2 -zstandard==0.23.0 +zstandard==0.25.0 diff --git a/st2common/st2common/config.py b/st2common/st2common/config.py index 28b0c062ec..c218122c7e 100644 --- a/st2common/st2common/config.py +++ b/st2common/st2common/config.py @@ -124,6 +124,15 @@ def register_opts(ignore_errors=False): default=False, help="True to validate action and runner output against schema.", ), + cfg.StrOpt( + "concurrency_library", + default="gevent", + choices=["eventlet", "gevent"], + help="Green thread concurrency library to use ('eventlet' or 'gevent'). " + "NOTE: This is read directly from this config file at process startup, " + "before oslo_config is available, so it cannot be overridden via CLI args " + "or environment variables.", + ), ] do_register_opts(system_opts, "system", ignore_errors) @@ -791,8 +800,8 @@ def register_opts(ignore_errors=False): cfg.BoolOpt( "use-debugger", default=True, - help="Enables debugger. Note that using this option changes how the " - "eventlet library is used to support async IO. This could result in " + help="Enables debugger. Note that using this option changes how the " + "concurrency library is used to support async IO. This could result in " "failures that do not occur under normal operation.", ), cfg.BoolOpt( @@ -801,14 +810,14 @@ def register_opts(ignore_errors=False): help="Enable code profiler mode. Do not use in production.", ), cfg.BoolOpt( - "enable-eventlet-blocking-detection", + "enable-concurrency-blocking-detection", default=False, - help="Enable eventlet blocking detection logic. Do not use in production.", + help="Enable blocking detection logic in concurrency library. Do not use in production.", ), cfg.FloatOpt( - "eventlet-blocking-detection-resolution", + "concurrency-blocking-detection-resolution", default=0.5, - help="Resolution in seconds for eventlet blocking detection logic.", + help="Resolution in seconds for blocking detection logic in currency library.", ), ] diff --git a/st2common/st2common/runners/parallel_ssh.py b/st2common/st2common/runners/parallel_ssh.py index 9aee991b0c..7c150d70d3 100644 --- a/st2common/st2common/runners/parallel_ssh.py +++ b/st2common/st2common/runners/parallel_ssh.py @@ -106,7 +106,8 @@ def connect(self, raise_on_any_error=False): for host in self._hosts: while not concurrency_lib.is_green_pool_free(self._pool): concurrency_lib.sleep(self._scan_interval) - self._pool.spawn( + concurrency_lib.pool_spawn( + self._pool, self._connect, host=host, results=results, @@ -242,9 +243,11 @@ def _execute_in_pool(self, execute_method, **kwargs): results[host] = self._bad_hosts[host] for host in self._hosts_client.keys(): - while not self._pool.free(): + while not concurrency_lib.is_green_pool_free(self._pool): concurrency_lib.sleep(self._scan_interval) - self._pool.spawn(execute_method, host=host, results=results, **kwargs) + concurrency_lib.pool_spawn( + self._pool, execute_method, host=host, results=results, **kwargs + ) concurrency_lib.green_pool_wait_all(self._pool) return results diff --git a/st2common/st2common/service_setup.py b/st2common/st2common/service_setup.py index 9e8ae7e07f..ff3b1fb350 100644 --- a/st2common/st2common/service_setup.py +++ b/st2common/st2common/service_setup.py @@ -1,4 +1,4 @@ -# Copyright 2020 The StackStorm Authors. +# Copyright 2020-2026 The StackStorm Authors. # Copyright 2019 Extreme Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,7 @@ import logging as stdlib_logging import six -import eventlet.debug + from oslo_config import cfg from tooz.coordination import GroupAlreadyExist from tooz.coordination import GroupNotCreated @@ -38,6 +38,7 @@ from st2common.transport.bootstrap_utils import register_kombu_serializers from st2common.bootstrap import runnersregistrar from st2common.signal_handlers import register_common_signal_handlers +from st2common.util.concurrency import blocking_detection from st2common.util.debugging import enable_debugging from st2common.models.utils.profiling import enable_profiling from st2common import triggers @@ -48,7 +49,7 @@ from st2common.logging.misc import add_global_filters_for_all_loggers from st2common.constants.error_messages import PYTHON2_DEPRECATION from st2common.services.coordination import get_driver_name -from st2common.util.profiler import setup_eventlet_profiler +from st2common.util.profiler import setup_green_profiler # Note: This is here for backward compatibility. # Function has been moved in a standalone module to avoid expensive in-direct @@ -127,7 +128,7 @@ def setup( config.parse_args() if cfg.CONF.enable_profiler: - setup_eventlet_profiler(service_name="st2" + service) + setup_green_profiler(service_name="st2" + service) version = "%s.%s.%s" % ( sys.version_info[0], @@ -285,11 +286,10 @@ def setup( # modules like jinja, stevedore, etc load files from disk on init which is slow and will be # detected as blocking operation, but this is not really an issue inside the service startup / # init phase. - if cfg.CONF.enable_eventlet_blocking_detection: - print("Eventlet long running / blocking operation detection logic enabled") - print(cfg.CONF.eventlet_blocking_detection_resolution) - eventlet.debug.hub_blocking_detection( - state=True, resolution=cfg.CONF.eventlet_blocking_detection_resolution + if cfg.CONF.enable_concurrency_blocking_detection: + blocking_detection( + cfg.CONF.enable_concurrency_blocking_detection, + cfg.CONF.concurrency_blocking_detection_resolution, ) diff --git a/st2common/st2common/stream/listener.py b/st2common/st2common/stream/listener.py index 5eb5dc8b8f..b79c2c477f 100644 --- a/st2common/st2common/stream/listener.py +++ b/st2common/st2common/stream/listener.py @@ -16,7 +16,7 @@ from __future__ import absolute_import import fnmatch -import eventlet +from st2common.util import concurrency from kombu.mixins import ConsumerMixin from oslo_config import cfg @@ -94,7 +94,7 @@ def generator( end_statuses=None, end_execution_id=None, ): - queue = eventlet.Queue() + queue = concurrency.Queue() queue.put("") self.queues.append(queue) try: @@ -144,7 +144,7 @@ def generator( continue yield message - except eventlet.queue.Empty: + except concurrency.get_queue_empty_exception(): yield finally: self.queues.remove(queue) @@ -273,13 +273,13 @@ def get_listener(name): if not _stream_listener: with transport_utils.get_connection() as conn: _stream_listener = StreamListener(conn) - eventlet.spawn_n(listen, _stream_listener) + concurrency.spawn(listen, _stream_listener) return _stream_listener elif name == "execution_output": if not _execution_output_listener: with transport_utils.get_connection() as conn: _execution_output_listener = ExecutionOutputListener(conn) - eventlet.spawn_n(listen, _execution_output_listener) + concurrency.spawn(listen, _execution_output_listener) return _execution_output_listener else: raise ValueError("Invalid listener name: %s" % (name)) diff --git a/st2common/st2common/transport/consumers.py b/st2common/st2common/transport/consumers.py index 82361f1aa8..db87e9b8b4 100644 --- a/st2common/st2common/transport/consumers.py +++ b/st2common/st2common/transport/consumers.py @@ -202,14 +202,14 @@ def start(self, wait=False): self.wait() def wait(self): - self._consumer_thread.wait() + return concurrency.wait(self._consumer_thread) def shutdown(self): LOG.info("Shutting down %s...", self.__class__.__name__) self._queue_consumer.shutdown() def kill(self): - self._consumer_thread.kill(SystemExit()) + concurrency.kill(self._consumer_thread, SystemExit()) @abc.abstractmethod def process(self, message): diff --git a/st2common/st2common/util/concurrency.py b/st2common/st2common/util/concurrency.py index f5a2212e43..50f9c3442f 100644 --- a/st2common/st2common/util/concurrency.py +++ b/st2common/st2common/util/concurrency.py @@ -1,4 +1,4 @@ -# Copyright 2020 The StackStorm Authors. +# Copyright 2020-2026 The StackStorm Authors. # Copyright 2019 Extreme Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,21 +17,14 @@ Module which acts as a compatibility later between eventlet and gevent. It dispatches function call to the concurrency library which is configured using -"set_concurrency_library" functoion. +"set_concurrency_library" function. """ -try: - import eventlet # pylint: disable=import-error -except ImportError: - eventlet = None +import configparser +import cProfile +import types -try: - import gevent # pylint: disable=import-error # pants: no-infer-dep - import gevent.pool -except ImportError: - gevent = None - -CONCURRENCY_LIBRARY = "eventlet" +from st2common.constants.system import DEFAULT_CONFIG_FILE_PATH __all__ = [ "set_concurrency_library", @@ -42,121 +35,318 @@ "wait", "cancel", "kill", + "link", "sleep", "get_greenlet_exit_exception_class", "get_green_pool_class", + "pool_spawn", + "resize_green_pool", "is_green_pool_free", "green_pool_wait_all", + "get_green_profiler", ] +_state = types.SimpleNamespace(library=None, eventlet=None, gevent=None) -def set_concurrency_library(library): - global CONCURRENCY_LIBRARY - if library not in ["eventlet", "gevent"]: +def _get_concurrency_library_from_conf(config_path=DEFAULT_CONFIG_FILE_PATH): + # NOTE: We can't use st2common.config/oslo_config here because eventlet/gevent + # monkey patching (see st2common.util.monkey_patch) must happen before almost + # anything else is imported, which is earlier than oslo_config can be parsed. + # This minimal read only depends on the stdlib. + parser = configparser.ConfigParser() + parser.read(config_path) # no-op if the file doesn't exist + try: + return parser.get("system", "concurrency_library") + except (configparser.NoSectionError, configparser.NoOptionError): + return "gevent" + + +def _import_eventlet(): + try: + import eventlet # pylint: disable=import-error + import eventlet.debug + import eventlet.green.profile + import eventlet.green.subprocess + import eventlet.wsgi + + return eventlet + except ImportError: + return None + + +def _import_gevent(): + try: + import gevent # pylint: disable=import-error # pants: no-infer-dep + import gevent.lock + import gevent.monkey + import gevent.pool + import gevent.pywsgi + import gevent.queue + import gevent.subprocess + + return gevent + except ImportError: + return None + + +def set_concurrency_library(library): + if library not in ("eventlet", "gevent"): raise ValueError("Unsupported concurrency library: %s" % (library)) - CONCURRENCY_LIBRARY = library + # Only import the library that's actually active. Importing eventlet unconditionally + # eagerly loads eventlet.green.ssl, subclassing ssl.SSLContext before + # gevent.monkey.patch_all() runs, which triggers a spurious MonkeyPatchWarning. + if library == "eventlet" and _state.eventlet is None: + _state.eventlet = _import_eventlet() + elif library == "gevent" and _state.gevent is None: + _state.gevent = _import_gevent() + + _state.library = library def get_concurrency_library(): - global CONCURRENCY_LIBRARY - return CONCURRENCY_LIBRARY + return _state.library -def get_subprocess_module(): - if CONCURRENCY_LIBRARY == "eventlet": - from eventlet.green import subprocess # pylint: disable=import-error +set_concurrency_library(_get_concurrency_library_from_conf()) - return subprocess - elif CONCURRENCY_LIBRARY == "gevent": - from gevent import subprocess # pylint: disable=import-error - return subprocess +def get_subprocess_module(): + if _state.library == "eventlet": + return _state.eventlet.green.subprocess + elif _state.library == "gevent": + return _state.gevent.subprocess + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") + + +def wsgi_server( + socket, app, custom_pool=None, log=None, log_output=True, *args, **kwargs +): + if _state.library == "eventlet": + _state.eventlet.wsgi.server( + socket, + app, + custom_pool=custom_pool, + log=log, + log_output=log_output, + *args, + **kwargs, + ) + elif _state.library == "gevent": + server = _state.gevent.pywsgi.WSGIServer( + socket, app, spawn=custom_pool, log=log + ) + server.serve_forever() + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") def subprocess_popen(*args, **kwargs): - if CONCURRENCY_LIBRARY == "eventlet": - from eventlet.green import subprocess # pylint: disable=import-error + if _state.library == "eventlet": + return _state.eventlet.green.subprocess.Popen(*args, **kwargs) + elif _state.library == "gevent": + return _state.gevent.subprocess.Popen(*args, **kwargs) + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") - return subprocess.Popen(*args, **kwargs) - elif CONCURRENCY_LIBRARY == "gevent": - from gevent import subprocess # pylint: disable=import-error - return subprocess.Popen(*args, **kwargs) +def spawn_after(seconds, func, *args, **kwargs): + if _state.library == "eventlet": + return _state.eventlet.spawn_after(seconds, func, *args, **kwargs) + elif _state.library == "gevent": + return _state.gevent.spawn_later(seconds, func, *args, **kwargs) + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") + + +def Semaphore(*args, **kwargs): + if _state.library == "eventlet": + return _state.eventlet.Semaphore(*args, **kwargs) + elif _state.library == "gevent": + return _state.gevent.lock.Semaphore(*args, **kwargs) + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") def spawn(func, *args, **kwargs): - if CONCURRENCY_LIBRARY == "eventlet": - return eventlet.spawn(func, *args, **kwargs) - elif CONCURRENCY_LIBRARY == "gevent": - return gevent.spawn(func, *args, **kwargs) + if _state.library == "eventlet": + return _state.eventlet.spawn(func, *args, **kwargs) + elif _state.library == "gevent": + return _state.gevent.spawn(func, *args, **kwargs) else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {_state.library}") def wait(green_thread, *args, **kwargs): - if CONCURRENCY_LIBRARY == "eventlet": + if _state.library == "eventlet": return green_thread.wait(*args, **kwargs) - elif CONCURRENCY_LIBRARY == "gevent": - return green_thread.join(*args, **kwargs) + elif _state.library == "gevent": + # NOTE: Greenlet.join() blocks but always returns None; .get() blocks + # and returns the greenlet's result (or re-raises its exception), + # matching eventlet's GreenThread.wait() semantics. + return green_thread.get(*args, **kwargs) else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {_state.library}") def cancel(green_thread, *args, **kwargs): - if CONCURRENCY_LIBRARY == "eventlet": + if _state.library == "eventlet": return green_thread.cancel(*args, **kwargs) - elif CONCURRENCY_LIBRARY == "gevent": + elif _state.library == "gevent": return green_thread.kill(*args, **kwargs) else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {_state.library}") + + +def link(green_thread, callback): + """ + Register a callback to run once the green thread finishes (whether it succeeded, failed, + or was killed). + """ + if _state.library in ("eventlet", "gevent"): + return green_thread.link(callback) + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") def kill(green_thread, *args, **kwargs): - if CONCURRENCY_LIBRARY == "eventlet": + if _state.library == "eventlet": return green_thread.kill(*args, **kwargs) - elif CONCURRENCY_LIBRARY == "gevent": + elif _state.library == "gevent": return green_thread.kill(*args, **kwargs) else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {_state.library}") + + +def listen(host, port): + return listen_server(host, port) + + +def Queue(*args, **kwargs): + if _state.library == "eventlet": + return _state.eventlet.Queue(*args, **kwargs) + elif _state.library == "gevent": + return _state.gevent.queue.Queue(*args, **kwargs) + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") + + +def get_queue_empty_exception(): + if _state.library == "eventlet": + return _state.eventlet.queue.Empty + elif _state.library == "gevent": + return _state.gevent.queue.Empty + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") def sleep(*args, **kwargs): - if CONCURRENCY_LIBRARY == "eventlet": - return eventlet.sleep(*args, **kwargs) - elif CONCURRENCY_LIBRARY == "gevent": - return gevent.sleep(*args, **kwargs) + if _state.library == "eventlet": + return _state.eventlet.sleep(*args, **kwargs) + elif _state.library == "gevent": + return _state.gevent.sleep(*args, **kwargs) else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {_state.library}") def get_greenlet_exit_exception_class(): - if CONCURRENCY_LIBRARY == "eventlet": - return eventlet.support.greenlets.GreenletExit - elif CONCURRENCY_LIBRARY == "gevent": - return gevent.GreenletExit + if _state.library == "eventlet": + return _state.eventlet.support.greenlets.GreenletExit + elif _state.library == "gevent": + return _state.gevent.GreenletExit + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") + + +def get_default_green_pool_size(): + if _state.library == "eventlet": + return _state.eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS + elif _state.library == "gevent": + # matches what DEFAULT_MAX_SIMULTANEOUS_REQUESTS is for eventlet + return 1024 else: raise ValueError("Unsupported concurrency library") def get_green_pool_class(): - if CONCURRENCY_LIBRARY == "eventlet": - return eventlet.GreenPool - elif CONCURRENCY_LIBRARY == "gevent": - return gevent.pool.Pool + if _state.library == "eventlet": + return _state.eventlet.GreenPool + elif _state.library == "gevent": + return _state.gevent.pool.Pool else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {_state.library}") -def is_green_pool_free(pool): +def pool_spawn(pool, func, *args, **kwargs): + """ + Spawn a green thread inside the given green pool (bounded concurrency), unlike spawn() + which spawns an unbounded green thread. + """ + if _state.library in ("eventlet", "gevent"): + return pool.spawn(func, *args, **kwargs) + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") + + +def resize_green_pool(pool, size): + """ + Resize a green pool's concurrency limit. + + gevent's Pool has no equivalent of eventlet's GreenPool.resize(): its internal semaphore + is fixed at construction time and never re-reads the (otherwise inert) .size attribute + afterwards, so this is a no-op under gevent. Callers that use this to stop a pool from + accepting new work should also close the pool's listening socket, which is what actually + prevents new work from arriving under either library. + """ + if _state.library == "eventlet": + pool.resize(size) + elif _state.library == "gevent": + pass + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") + + +def green_pool_free_count(pool): """ - Return True if the provided green pool is free, False otherwise. + Return the number of free slots in the pool. """ - if CONCURRENCY_LIBRARY == "eventlet": + if _state.library == "eventlet": return pool.free() - elif CONCURRENCY_LIBRARY == "gevent": - return not pool.full() + elif _state.library == "gevent": + return pool.free_count() + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") + + +def is_green_pool_free(pool): + """ + Return True if the provided green pool has at least one free slot, False otherwise. + """ + return green_pool_free_count(pool) > 0 + + +def green_pool_running_count(pool): + """ + Return the number of greenlets currently running in the pool. + """ + if _state.library == "eventlet": + return pool.running() + elif _state.library == "gevent": + return len(pool.greenlets) + else: + raise ValueError("Unsupported concurrency library") + + +def get_pool_greenlets(pool): + """ + Return the set of currently running greenlets in the pool. + """ + if _state.library == "eventlet": + return pool.coroutines_running + elif _state.library == "gevent": + return pool.greenlets else: raise ValueError("Unsupported concurrency library") @@ -165,11 +355,94 @@ def green_pool_wait_all(pool): """ Wait for all the green threads in the pool to finish. """ - if CONCURRENCY_LIBRARY == "eventlet": + if _state.library == "eventlet": return pool.waitall() - elif CONCURRENCY_LIBRARY == "gevent": - # NOTE: This mimicks eventlet.waitall() functionallity better than - # pool.join() - return all(gl.ready() for gl in pool.greenlets) + elif _state.library == "gevent": + return pool.join() + else: + raise ValueError("Unsupported concurrency library") + + +def listen_server(host, port, backlog=50, **kwargs): + """ + Start listening on the host:port. + :backlog: the number of unaccepted connections that the system will allow before refusing new connections. + """ + if _state.library == "eventlet": + return _state.eventlet.listen((host, port), backlog=backlog, **kwargs) + elif _state.library == "gevent": + import socket + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind((host, port)) + sock.listen(backlog) + return sock + else: + raise ValueError("Unsupported concurrency library") + + +def wrap_ssl(socket, *args, **kwargs): + if _state.library == "eventlet": + return _state.eventlet.wrap_ssl(socket, *args, **kwargs) + elif _state.library == "gevent": + # Monkey patching in the caller module is required prior to + # calling wrap_ssl() or this may block. + import ssl + + server_side = kwargs.pop("server_side", False) + certfile = kwargs.pop("certfile", None) + keyfile = kwargs.pop("keyfile", None) + + protocol = ssl.PROTOCOL_TLS_SERVER if server_side else ssl.PROTOCOL_TLS_CLIENT + context = ssl.SSLContext(protocol) + if certfile: + context.load_cert_chain(certfile, keyfile) + + return context.wrap_socket(socket, *args, server_side=server_side, **kwargs) + else: + raise ValueError("Unsupported concurrency library") + + +def get_green_profiler(): + """ + Return a (profiler, start, stop) tuple for a green-thread-aware profiler. + + Only to be used with eventlet/gevent code (aka a StackStorm service minus the CLI). + """ + if _state.library == "eventlet": + if not _state.eventlet.patcher.is_monkey_patched("os"): + raise ValueError( + "No eventlet monkey patching detected. Code may not be using eventlet" + ) + + profiler = _state.eventlet.green.profile.Profile() + return profiler, profiler.start, profiler.stop + elif _state.library == "gevent": + if not _state.gevent.monkey.is_module_patched("os"): + raise ValueError( + "No gevent monkey patching detected. Code may not be using gevent" + ) + + # gevent doesn't ship a greenlet-aware profile module; regular cProfile works fine + # since gevent greenlets are cooperative and run on a single OS thread. + profiler = cProfile.Profile() + return profiler, profiler.enable, profiler.disable + else: + raise ValueError(f"Unsupported concurrency library {_state.library}") + + +def blocking_detection(enable=False, timeout=1.0): + if _state.library == "eventlet": + print( + f"Eventlet long running / blocking operation detection logic enabled. Block timeout ({timeout})." + ) + _state.eventlet.debug.hub_blocking_detection(state=enable, resolution=timeout) + elif _state.library == "gevent": + print( + f"gEvent long running / blocking operation detection logic enabled. Block timeout ({timeout})." + ) + _state.gevent.config.monitor_thread = enable + _state.gevent.config.max_blocking_time = timeout else: raise ValueError("Unsupported concurrency library") diff --git a/st2common/st2common/util/green/shell.py b/st2common/st2common/util/green/shell.py index 64830c9423..3aef24432c 100644 --- a/st2common/st2common/util/green/shell.py +++ b/st2common/st2common/util/green/shell.py @@ -204,6 +204,8 @@ def on_timeout_expired(timeout): stdin_value = stdin_value.encode("utf-8") process.stdin.write(stdin_value) + # Without closing, large writes can hang under gevent (child never sees the data). + process.stdin.close() if read_stdout_func and read_stderr_func: LOG.debug("Using real-time stdout and stderr read mode, calling process.wait()") diff --git a/st2common/st2common/util/greenpooldispatch.py b/st2common/st2common/util/greenpooldispatch.py index 156d530116..81eb52656b 100644 --- a/st2common/st2common/util/greenpooldispatch.py +++ b/st2common/st2common/util/greenpooldispatch.py @@ -16,9 +16,10 @@ from __future__ import absolute_import import time -import eventlet import six.moves.queue +from st2common.util import concurrency + from st2common import log as logging __all__ = ["BufferedDispatcher"] @@ -44,8 +45,8 @@ def __init__( name=None, ): self._pool_limit = dispatch_pool_size - self._dispatcher_pool = eventlet.GreenPool(dispatch_pool_size) - self._dispatch_monitor_thread = eventlet.greenthread.spawn(self._flush) + self._dispatcher_pool = concurrency.get_green_pool_class()(dispatch_pool_size) + self._dispatch_monitor_thread = concurrency.spawn(self._flush) self._monitor_thread_empty_q_sleep_time = monitor_thread_empty_q_sleep_time self._monitor_thread_no_workers_sleep_time = ( monitor_thread_no_workers_sleep_time @@ -66,18 +67,18 @@ def dispatch(self, handler, *args): self._flush_now() def shutdown(self): - self._dispatch_monitor_thread.kill() + concurrency.kill(self._dispatch_monitor_thread) def _flush(self): while True: while self._work_buffer.empty(): - eventlet.greenthread.sleep(self._monitor_thread_empty_q_sleep_time) - while self._dispatcher_pool.free() <= 0: - eventlet.greenthread.sleep(self._monitor_thread_no_workers_sleep_time) + concurrency.sleep(self._monitor_thread_empty_q_sleep_time) + while not concurrency.is_green_pool_free(self._dispatcher_pool): + concurrency.sleep(self._monitor_thread_no_workers_sleep_time) self._flush_now() def _flush_now(self): - if self._dispatcher_pool.free() <= 0: + if not concurrency.is_green_pool_free(self._dispatcher_pool): now = time.time() if (now - self._pool_last_free_ts) >= POOL_BUSY_THRESHOLD_SECONDS: @@ -90,12 +91,14 @@ def _flush_now(self): # Update the time of when there were free threads available self._pool_last_free_ts = time.time() - while not self._work_buffer.empty() and self._dispatcher_pool.free() > 0: + while not self._work_buffer.empty() and concurrency.is_green_pool_free( + self._dispatcher_pool + ): (handler, args) = self._work_buffer.get_nowait() - self._dispatcher_pool.spawn(handler, *args) + concurrency.pool_spawn(self._dispatcher_pool, handler, *args) def __repr__(self): - free_count = self._dispatcher_pool.free() + free_count = concurrency.green_pool_free_count(self._dispatcher_pool) values = ( self.name, self._pool_limit, diff --git a/st2common/st2common/util/monkey_patch.py b/st2common/st2common/util/monkey_patch.py index ceb430592d..79c63582de 100644 --- a/st2common/st2common/util/monkey_patch.py +++ b/st2common/st2common/util/monkey_patch.py @@ -18,6 +18,7 @@ """ from __future__ import absolute_import +from st2common.util.concurrency import get_concurrency_library import os import sys @@ -45,15 +46,25 @@ def monkey_patch(patch_thread=None): patched unless debugger is used. :type patch_thread: ``bool`` """ - import eventlet + concurrency_library = get_concurrency_library() + if concurrency_library == "eventlet": + import eventlet - if patch_thread is None: - patch_thread = not is_use_debugger_flag_provided() + if patch_thread is None: + patch_thread = not is_use_debugger_flag_provided() - # TODO: support gevent.patch_all if .concurrency.CONCURRENCY_LIBRARY = "gevent" - eventlet.monkey_patch( - os=True, select=True, socket=True, thread=patch_thread, time=True - ) + eventlet.monkey_patch( + os=True, select=True, socket=True, thread=patch_thread, time=True + ) + elif concurrency_library == "gevent": + # Match what eventlet was enabling, fallback on gevent defaults + import gevent + + gevent.monkey.patch_all( + os=True, select=True, thread=True, time=True, socket=True + ) + else: + raise RuntimeError(f"Unsupported concurrency library {concurrency_library}") def use_select_poll_workaround(nose_only=True): @@ -79,30 +90,31 @@ def use_select_poll_workaround(nose_only=True): runner. :type nose_only: ``bool`` """ - import sys - import select - import subprocess - import eventlet - - # Work around to get tests to pass with eventlet >= 0.20.0 - if not nose_only or ( - nose_only - # sys._called_from_test set in conftest.py for pytest runs - and ("nose" in sys.modules.keys() or hasattr(sys, "_called_from_test")) - ): - # Add back blocking poll() to eventlet monkeypatched select - original_poll = eventlet.patcher.original("select").poll - select.poll = original_poll - - sys.modules["select"] = select - subprocess.select = select - - if sys.version_info >= (3, 6, 5): - # If we also don't patch selectors.select, it will fail with Python >= 3.6.5 - import selectors # pylint: disable=import-error - - sys.modules["selectors"] = selectors - selectors.select = sys.modules["select"] + if get_concurrency_library() == "eventlet": + import sys + import select + import subprocess + import eventlet + + # Work around to get tests to pass with eventlet >= 0.20.0 + if not nose_only or ( + nose_only + # sys._called_from_test set in conftest.py for pytest runs + and ("nose" in sys.modules.keys() or hasattr(sys, "_called_from_test")) + ): + # Add back blocking poll() to eventlet monkeypatched select + original_poll = eventlet.patcher.original("select").poll + select.poll = original_poll + + sys.modules["select"] = select + subprocess.select = select + + if sys.version_info >= (3, 6, 5): + # If we also don't patch selectors.select, it will fail with Python >= 3.6.5 + import selectors # pylint: disable=import-error + + sys.modules["selectors"] = selectors + selectors.select = sys.modules["select"] def is_use_debugger_flag_provided(): diff --git a/st2common/st2common/util/profiler.py b/st2common/st2common/util/profiler.py index b8760a2046..49c866d384 100644 --- a/st2common/st2common/util/profiler.py +++ b/st2common/st2common/util/profiler.py @@ -19,10 +19,9 @@ import platform import cProfile -import eventlet -from eventlet.green import profile +from st2common.util import concurrency -__all__ = ["setup_regular_profiler", "setup_eventlet_profiler"] +__all__ = ["setup_regular_profiler", "setup_green_profiler", "setup_eventlet_profiler"] def setup_regular_profiler(service_name: str) -> None: @@ -49,20 +48,14 @@ def stop_profiler(): atexit.register(stop_profiler) -def setup_eventlet_profiler(service_name: str) -> None: +def setup_green_profiler(service_name: str) -> None: """ - Set up eventlet profiler and write results to a file on exit. + Set up a green-thread (eventlet/gevent) aware profiler and write results to a file on exit. - Only to be used with eventlet code (aka an StackStorm service minus the CLI). + Only to be used with eventlet/gevent code (aka a StackStorm service minus the CLI). """ - is_patched = eventlet.patcher.is_monkey_patched("os") - if not is_patched: - raise ValueError( - "No eventlet monkey patching detected. Code may not be using eventlet" - ) - - profiler = profile.Profile() - profiler.start() + profiler, start, stop = concurrency.get_green_profiler() + start() file_path = os.path.join( "/tmp", "%s-%s-%s.cprof" % (service_name, platform.machine(), int(time.time())) @@ -72,10 +65,15 @@ def setup_eventlet_profiler(service_name: str) -> None: print("Profiling data will be saved to %s on exit" % (file_path)) def stop_profiler(): - profiler.stop() + stop() profiler.dump_stats(file_path) print("Profiling data written to %s" % (file_path)) print("You can view it using: ") print("\t python3 -m pstats %s" % (file_path)) atexit.register(stop_profiler) + + +def setup_eventlet_profiler(service_name: str) -> None: + """Deprecated alias for setup_green_profiler(), kept for external callers.""" + return setup_green_profiler(service_name) diff --git a/st2common/st2common/util/shell.py b/st2common/st2common/util/shell.py index 171085be74..7259f180ad 100644 --- a/st2common/st2common/util/shell.py +++ b/st2common/st2common/util/shell.py @@ -124,9 +124,9 @@ def kill_process(process): try: if six.PY3: - status = subprocess.call( + status = subprocess.call( # pylint: disable=not-callable kill_command, timeout=100 - ) # pylint: disable=not-callable + ) else: status = subprocess.call(kill_command) # pylint: disable=not-callable except Exception: diff --git a/st2common/st2common/util/wsgi.py b/st2common/st2common/util/wsgi.py index 63ec6c6253..23e18357a0 100644 --- a/st2common/st2common/util/wsgi.py +++ b/st2common/st2common/util/wsgi.py @@ -14,13 +14,13 @@ # limitations under the License. """ -Eventlet WSGI server related utility functions. +WSGI server related utility functions. """ from __future__ import absolute_import -import eventlet from st2common import log as logging +from st2common.util import concurrency LOG = logging.getLogger(__name__) @@ -40,20 +40,20 @@ def shutdown_server_kill_pending_requests(sock, worker_pool, wait_time=2): forcefully killing them. :type wait_time: ``int`` """ - worker_pool.resize(0) + concurrency.resize_green_pool(worker_pool, 0) sock.close() - active_requests = worker_pool.running() + active_requests = concurrency.green_pool_running_count(worker_pool) LOG.info("Shutting down. Requests left: %s", active_requests) # Give active requests some time to finish if active_requests > 0: - eventlet.sleep(wait_time) + concurrency.sleep(wait_time) # Kill requests which still didn't finish - running_corutines = worker_pool.coroutines_running.copy() - for coro in running_corutines: - eventlet.greenthread.kill(coro) + running_greenlets = concurrency.get_pool_greenlets(worker_pool).copy() + for coro in running_greenlets: + concurrency.kill(coro) LOG.info("Exiting...") raise SystemExit() diff --git a/st2common/tests/integration/test_logging.py b/st2common/tests/integration/test_logging.py index 87852914d9..019987f06e 100644 --- a/st2common/tests/integration/test_logging.py +++ b/st2common/tests/integration/test_logging.py @@ -26,8 +26,9 @@ import signal import pytest -import eventlet -from eventlet.green import subprocess +from st2common.util import concurrency + +subprocess = concurrency.get_subprocess_module() from st2tests.base import IntegrationTestCase @@ -55,7 +56,7 @@ def test_formatting_with_unicode_data_works_no_stdout_patching_valid_utf8_encodi self.add_process(process=process) # Give it some time to start up and run for a while - eventlet.sleep(2) + concurrency.sleep(2) process.send_signal(signal.SIGKILL) stdout = process.stdout.read().decode("utf-8").strip() @@ -98,7 +99,7 @@ def test_formatting_with_unicode_data_works_no_stdout_patching_non_valid_utf8_en self.add_process(process=process) # Give it some time to start up and run for a while - eventlet.sleep(2) + concurrency.sleep(2) process.send_signal(signal.SIGKILL) stdout = process.stdout.read().decode("utf-8") @@ -144,7 +145,7 @@ def test_formatting_with_unicode_data_works_no_stdout_patching_ascii_pythonioenc self.add_process(process=process) # Give it some time to start up and run for a while - eventlet.sleep(2) + concurrency.sleep(2) process.send_signal(signal.SIGKILL) stdout = process.stdout.read().decode("utf-8") @@ -188,7 +189,7 @@ def test_formatting_with_unicode_data_works_with_stdout_patching_valid_utf8_enco self.add_process(process=process) # Give it some time to start up and run for a while - eventlet.sleep(2) + concurrency.sleep(2) process.send_signal(signal.SIGKILL) stdout = process.stdout.read().decode("utf-8") @@ -224,7 +225,7 @@ def test_formatting_with_unicode_data_works_with_stdout_patching_non_valid_utf8_ self.add_process(process=process) # Give it some time to start up and run for a while - eventlet.sleep(2) + concurrency.sleep(2) process.send_signal(signal.SIGKILL) stdout = process.stdout.read().decode("utf-8") @@ -261,7 +262,7 @@ def test_formatting_with_unicode_data_works_with_stdout_patching__ascii_pythonio self.add_process(process=process) # Give it some time to start up and run for a while - eventlet.sleep(2) + concurrency.sleep(2) process.send_signal(signal.SIGKILL) stdout = process.stdout.read().decode("utf-8") diff --git a/st2common/tests/integration/test_service_setup_log_level_filtering.py b/st2common/tests/integration/test_service_setup_log_level_filtering.py index f55214212a..cf5d3b87c4 100644 --- a/st2common/tests/integration/test_service_setup_log_level_filtering.py +++ b/st2common/tests/integration/test_service_setup_log_level_filtering.py @@ -18,8 +18,9 @@ import sys import signal -import eventlet -from eventlet.green import subprocess +from st2common.util import concurrency + +subprocess = concurrency.get_subprocess_module() import st2tests.config from st2tests.base import IntegrationTestCase @@ -83,7 +84,7 @@ def test_system_info_is_logged_on_startup(self): self.add_process(process=process) # Give it some time to start up - eventlet.sleep(8) + concurrency.sleep(8) process.send_signal(signal.SIGTERM) # Verify first 4 environment related log messages @@ -105,7 +106,7 @@ def test_warning_is_emitted_on_non_utf8_encoding(self): self.add_process(process=process) # Give it some time to start up - eventlet.sleep(8) + concurrency.sleep(8) process.send_signal(signal.SIGTERM) # Verify first 4 environment related log messages @@ -126,7 +127,7 @@ def test_audit_log_level_is_filtered_if_log_level_is_not_debug_or_audit(self): self.add_process(process=process) # Give it some time to start up - eventlet.sleep(8) + concurrency.sleep(8) process.send_signal(signal.SIGTERM) # Verify first 4 environment related log messages @@ -143,7 +144,7 @@ def test_audit_log_level_is_filtered_if_log_level_is_not_debug_or_audit(self): self.add_process(process=process) # Give it some time to start up - eventlet.sleep(8) + concurrency.sleep(8) process.send_signal(signal.SIGTERM) # First 6 log lines are debug messages about the environment which are always logged @@ -158,7 +159,7 @@ def test_audit_log_level_is_filtered_if_log_level_is_not_debug_or_audit(self): self.add_process(process=process) # Give it some time to start up - eventlet.sleep(8) + concurrency.sleep(8) process.send_signal(signal.SIGTERM) # First 6 log lines are debug messages about the environment which are always logged @@ -173,7 +174,7 @@ def test_audit_log_level_is_filtered_if_log_level_is_not_debug_or_audit(self): self.add_process(process=process) # Give it some time to start up - eventlet.sleep(8) + concurrency.sleep(8) process.send_signal(signal.SIGTERM) # First 6 log lines are debug messages about the environment which are always logged @@ -188,7 +189,7 @@ def test_audit_log_level_is_filtered_if_log_level_is_not_debug_or_audit(self): self.add_process(process=process) # Give it some time to start up - eventlet.sleep(8) + concurrency.sleep(8) process.send_signal(signal.SIGTERM) # First 6 log lines are debug messages about the environment which are always logged @@ -207,7 +208,7 @@ def test_kombu_heartbeat_tick_log_messages_are_excluded(self): self.add_process(process=process) # Give it some time to start up - eventlet.sleep(8) + concurrency.sleep(8) process.send_signal(signal.SIGTERM) stdout = "\n".join(process.stdout.read().decode("utf-8").split("\n")) @@ -218,7 +219,7 @@ def test_kombu_heartbeat_tick_log_messages_are_excluded(self): self.add_process(process=process) # Give it some time to start up - eventlet.sleep(8) + concurrency.sleep(8) process.send_signal(signal.SIGTERM) stdout = "\n".join(process.stdout.read().decode("utf-8").split("\n")) diff --git a/st2common/tests/unit/test_greenpooldispatch.py b/st2common/tests/unit/test_greenpooldispatch.py index f77ae2937e..8ad17c2b17 100644 --- a/st2common/tests/unit/test_greenpooldispatch.py +++ b/st2common/tests/unit/test_greenpooldispatch.py @@ -14,9 +14,9 @@ # limitations under the License. from __future__ import absolute_import -import eventlet import mock +from st2common.util import concurrency from st2common.util.greenpooldispatch import BufferedDispatcher from unittest import TestCase from six.moves import range @@ -31,7 +31,7 @@ def test_dispatch_simple(self): dispatcher.dispatch(mock_handler, i, i + 1) expected.append((i, i + 1)) while mock_handler.call_count < 10: - eventlet.sleep(0.01) + concurrency.sleep(0.01) dispatcher.shutdown() call_args_list = [ (args[0][0], args[0][1]) for args in mock_handler.call_args_list @@ -50,7 +50,7 @@ def test_dispatch_starved(self): dispatcher.dispatch(mock_handler, i, i + 1) expected.append((i, i + 1)) while mock_handler.call_count < 10: - eventlet.sleep(0.01) + concurrency.sleep(0.01) dispatcher.shutdown() call_args_list = [ (args[0][0], args[0][1]) for args in mock_handler.call_args_list diff --git a/st2common/tests/unit/test_stream_generator.py b/st2common/tests/unit/test_stream_generator.py index 39a67621b5..ad5997d7ed 100644 --- a/st2common/tests/unit/test_stream_generator.py +++ b/st2common/tests/unit/test_stream_generator.py @@ -54,7 +54,7 @@ def get_consumers(self, consumer, channel): class TestStream(unittest.TestCase): @mock.patch("st2common.stream.listener.BaseListener._get_action_ref_for_body") - @mock.patch("eventlet.Queue") + @mock.patch("st2common.util.concurrency.Queue") def test_generator(self, mock_queue, get_action_ref_for_body): get_action_ref_for_body.return_value = None mock_queue.return_value = MockQueue() diff --git a/st2common/tests/unit/test_transport.py b/st2common/tests/unit/test_transport.py index 71d18e6010..1b05dbb0ff 100644 --- a/st2common/tests/unit/test_transport.py +++ b/st2common/tests/unit/test_transport.py @@ -21,7 +21,8 @@ import random import unittest -import eventlet + +from st2common.util import concurrency from bson.objectid import ObjectId from kombu.mixins import ConsumerMixin @@ -77,16 +78,16 @@ def test_publish_compression(self): with transport_utils.get_connection() as connection: connection.connect() watcher = QueueConsumer(connection=connection, queue=queue) - watcher_thread = eventlet.greenthread.spawn(watcher.run) + watcher_thread = concurrency.spawn(watcher.run) # Give it some time to start up since we are publishing on a new queue - eventlet.sleep(0.5) + concurrency.sleep(0.5) self.assertEqual(len(watcher.received_messages), 0) # 1. Verify compression is off as a default publisher.publish(payload=live_action_db, exchange=exchange) - eventlet.sleep(0.2) + concurrency.sleep(0.2) self.assertEqual(len(watcher.received_messages), 1) self.assertEqual( @@ -105,7 +106,7 @@ def test_publish_compression(self): cfg.CONF.set_override(name="compression", group="messaging", override="zstd") publisher.publish(payload=live_action_db, exchange=exchange) - eventlet.sleep(0.2) + concurrency.sleep(0.2) self.assertEqual(len(watcher.received_messages), 2) self.assertEqual( @@ -125,7 +126,7 @@ def test_publish_compression(self): cfg.CONF.set_override(name="compression", group="messaging", override="zstd") publisher.publish(payload=live_action_db, exchange=exchange, compression="gzip") - eventlet.sleep(0.2) + concurrency.sleep(0.2) self.assertEqual(len(watcher.received_messages), 3) self.assertEqual( @@ -141,7 +142,7 @@ def test_publish_compression(self): ) self.assertEqual(watcher.received_messages[2][0].id, live_action_db.id) - watcher_thread.kill() + concurrency.kill(watcher_thread) def test_get_ssl_kwargs(self): # 1. No SSL kwargs provided diff --git a/st2reactor/in-requirements.txt b/st2reactor/in-requirements.txt index e1bccfac12..a2865114e9 100644 --- a/st2reactor/in-requirements.txt +++ b/st2reactor/in-requirements.txt @@ -2,6 +2,7 @@ apscheduler python-dateutil eventlet +gevent jsonpath-rw jsonschema kombu diff --git a/st2reactor/requirements.txt b/st2reactor/requirements.txt index 2442b957bc..e10bf170f5 100644 --- a/st2reactor/requirements.txt +++ b/st2reactor/requirements.txt @@ -5,12 +5,13 @@ # If you want to update depdencies for a single component, modify the # in-requirements.txt for that component and then run 'make requirements' to # update the component requirements.txt -apscheduler==3.11.0 +apscheduler==3.11.3 backports.zoneinfo[tzdata]; python_version<"3.9" -eventlet==0.40.3 +eventlet==0.41.2 +gevent==26.8.0 jsonpath-rw==1.4.0 jsonschema==4.26.0 -kombu==5.5.4 +kombu==5.6.2 oslo.config==9.6.0 python-dateutil==2.9.0.post0 six==1.17.0 diff --git a/st2reactor/st2reactor/cmd/rulesengine.py b/st2reactor/st2reactor/cmd/rulesengine.py index cefe58f584..9ee98556ec 100644 --- a/st2reactor/st2reactor/cmd/rulesengine.py +++ b/st2reactor/st2reactor/cmd/rulesengine.py @@ -27,10 +27,10 @@ from st2common.service_setup import setup as common_setup from st2common.service_setup import teardown as common_teardown from st2common.service_setup import deregister_service +from st2common.util import concurrency from st2reactor.rules import config from st2reactor.rules import worker - LOGGER_NAME = get_logger_name_for_module(sys.modules[__name__]) LOG = logging.getLogger(LOGGER_NAME) RULESENGINE = "rulesengine" @@ -64,8 +64,6 @@ def _run_worker(): rules_engine_worker.start() # Monitor the worker thread - if it dies/fails, we need to exit cleanly - import eventlet - # Poll the worker thread to detect failures while True: if ( @@ -74,7 +72,9 @@ def _run_worker(): ): # Thread died - try to get the exception if it raised one try: - rules_engine_worker._consumer_thread.wait() # This will raise if thread raised + concurrency.wait( + rules_engine_worker._consumer_thread + ) # This will raise if thread raised except Exception as e: LOG.error("RulesEngine worker thread failed: %s", e) raise @@ -83,7 +83,7 @@ def _run_worker(): return 0 # Sleep briefly to avoid tight loop - eventlet.sleep(0.1) + concurrency.sleep(0.1) except (KeyboardInterrupt, SystemExit): LOG.info("(PID=%s) RulesEngine stopped.", os.getpid()) deregister_service(RULESENGINE) diff --git a/st2reactor/st2reactor/cmd/timersengine.py b/st2reactor/st2reactor/cmd/timersengine.py index 49f91f949c..f85b2ebe98 100644 --- a/st2reactor/st2reactor/cmd/timersengine.py +++ b/st2reactor/st2reactor/cmd/timersengine.py @@ -75,7 +75,7 @@ def _run_worker(): timer = St2Timer(local_timezone=local_tz) timer_thread = concurrency.spawn(_kickoff_timer, timer) LOG.info(TIMER_ENABLED_LOG_LINE) - return timer_thread.wait() + return concurrency.wait(timer_thread) else: LOG.info(TIMER_DISABLED_LOG_LINE) except (KeyboardInterrupt, SystemExit): diff --git a/st2reactor/st2reactor/container/manager.py b/st2reactor/st2reactor/container/manager.py index e9f251aebc..e833000d9c 100644 --- a/st2reactor/st2reactor/container/manager.py +++ b/st2reactor/st2reactor/container/manager.py @@ -83,7 +83,7 @@ def _spin_container_and_wait(self, sensors): LOG.debug("Starting sensor CUD watcher...") self._sensors_watcher.start() - exit_code = self._container_thread.wait() + exit_code = concurrency.wait(self._container_thread) LOG.error("Process container quit with exit_code %d.", exit_code) LOG.error("(PID:%s) SensorContainer stopped.", os.getpid()) except (KeyboardInterrupt, SystemExit): diff --git a/st2reactor/tests/unit/test_process_container.py b/st2reactor/tests/unit/test_process_container.py index 747618a4f0..d041198a9c 100644 --- a/st2reactor/tests/unit/test_process_container.py +++ b/st2reactor/tests/unit/test_process_container.py @@ -48,7 +48,7 @@ def test_no_sensors_dont_quit(self): self.assertEqual(process_container.running(), 0) self.assertEqual(process_container.stopped(), False) process_container.shutdown() - process_container_thread.kill() + concurrency.kill(process_container_thread) @patch.object( ProcessSensorContainer, diff --git a/st2reactor/tests/unit/test_rulesengine_shutdown_on_rabbitmq_failure.py b/st2reactor/tests/unit/test_rulesengine_shutdown_on_rabbitmq_failure.py index 04e510e2c4..bf9ff1e1ea 100644 --- a/st2reactor/tests/unit/test_rulesengine_shutdown_on_rabbitmq_failure.py +++ b/st2reactor/tests/unit/test_rulesengine_shutdown_on_rabbitmq_failure.py @@ -19,11 +19,11 @@ from __future__ import absolute_import -import eventlet import mock from kombu.exceptions import OperationalError as KombuOperationalError +from st2common.util import concurrency from st2reactor.cmd.rulesengine import _run_worker from st2reactor.rules.worker import TriggerInstanceDispatcher from st2tests.base import CleanDbTestCase @@ -47,11 +47,11 @@ def test_rulesengine_connection_error_propagates(self, mock_get_connection): mock_get_connection.side_effect = KombuOperationalError("Connection refused") # Run the worker in a greenthread - run_thread = eventlet.spawn(_run_worker) + run_thread = concurrency.spawn(_run_worker) # The worker should raise the connection error with self.assertRaises(KombuOperationalError) as cm: - run_thread.wait() + concurrency.wait(run_thread) self.assertIn("Connection refused", str(cm.exception)) @@ -67,17 +67,17 @@ def test_rulesengine_shuts_down_when_worker_thread_fails( def mock_start_that_fails(): # Simulate the worker thread starting but then failing - eventlet.sleep(0.1) + concurrency.sleep(0.1) raise RuntimeError("Worker thread failed") mock_start.side_effect = mock_start_that_fails # Run the worker - run_thread = eventlet.spawn(_run_worker) + run_thread = concurrency.spawn(_run_worker) # Should raise the RuntimeError from the worker thread with self.assertRaises(RuntimeError) as cm: - run_thread.wait() + concurrency.wait(run_thread) self.assertIn("Worker thread failed", str(cm.exception)) @@ -98,10 +98,10 @@ def test_rulesengine_handles_connection_retry_exhaustion( "Failed to connect after 10 attempts" ) - run_thread = eventlet.spawn(_run_worker) + run_thread = concurrency.spawn(_run_worker) # Should raise the connection error with self.assertRaises(KombuOperationalError) as cm: - run_thread.wait() + concurrency.wait(run_thread) self.assertIn("Failed to connect", str(cm.exception)) diff --git a/st2reactor/tests/unit/test_sensor_wrapper.py b/st2reactor/tests/unit/test_sensor_wrapper.py index 36b8c04f10..16ae747d23 100644 --- a/st2reactor/tests/unit/test_sensor_wrapper.py +++ b/st2reactor/tests/unit/test_sensor_wrapper.py @@ -26,6 +26,8 @@ import mock import eventlet +from st2common.util import concurrency + import st2tests.config as tests_config from st2tests.base import TESTS_CONFIG_PATH @@ -203,6 +205,11 @@ def test_sensor_wrapper_poll_method_still_works(self): # 'poll'" will be thrown import select - self.assertTrue(eventlet.patcher.is_monkey_patched(select)) - self.assertTrue(select != eventlet.patcher.original("select")) + if concurrency.get_concurrency_library() == "eventlet": + self.assertTrue(eventlet.patcher.is_monkey_patched(select)) + self.assertTrue(select != eventlet.patcher.original("select")) + else: + import gevent.monkey + + self.assertTrue(gevent.monkey.is_module_patched("select")) self.assertTrue(select.poll()) diff --git a/st2reactor/tests/unit/test_timer.py b/st2reactor/tests/unit/test_timer.py index 9ec00be5ec..053e0fba23 100644 --- a/st2reactor/tests/unit/test_timer.py +++ b/st2reactor/tests/unit/test_timer.py @@ -22,6 +22,7 @@ from st2common.models.system.common import ResourceReference from st2common.persistence.trigger import TriggerType from st2common.persistence.trigger import Trigger +from st2common.util import concurrency from st2reactor.timer.base import St2Timer from st2tests.base import CleanDbTestCase @@ -75,7 +76,7 @@ def test_existing_rules_are_loaded_on_start(self): self.assertEqual(len(Trigger.get_all()), 1) timer.start() - timer._trigger_watcher._load_thread.wait() + concurrency.wait(timer._trigger_watcher._load_thread) # Verify handlers are called timer._handle_create_trigger.assert_called_with(trigger_db) diff --git a/st2stream/in-requirements.txt b/st2stream/in-requirements.txt index 273a2b1b2f..7671b1712b 100644 --- a/st2stream/in-requirements.txt +++ b/st2stream/in-requirements.txt @@ -1,5 +1,6 @@ # Remember to list implicit packages here, otherwise version won't be fixated! eventlet +gevent jsonschema kombu mongoengine diff --git a/st2stream/requirements.txt b/st2stream/requirements.txt index 184c7f79e4..0276eda776 100644 --- a/st2stream/requirements.txt +++ b/st2stream/requirements.txt @@ -6,13 +6,14 @@ # in-requirements.txt for that component and then run 'make requirements' to # update the component requirements.txt backports.zoneinfo[tzdata]; python_version<"3.9" -eventlet==0.40.3 -gunicorn<26 +eventlet==0.41.2 +gevent==26.8.0 +gunicorn==25.3.0 jsonschema==4.26.0 -kombu==5.5.4 -mongoengine==0.29.1 +kombu==5.6.2 +mongoengine==0.29.3 oslo.config==9.6.0 oslo.utils==7.3.0 pymongo==4.6.3 -pyparsing==3.1.4 +pyparsing==3.3.2 six==1.17.0 diff --git a/st2stream/st2stream/cmd/api.py b/st2stream/st2stream/cmd/api.py index 3de0c89f03..cbc3cd11d7 100644 --- a/st2stream/st2stream/cmd/api.py +++ b/st2stream/st2stream/cmd/api.py @@ -1,4 +1,4 @@ -# Copyright 2020 The StackStorm Authors. +# Copyright 2020-2026 The StackStorm Authors. # Copyright 2019 Extreme Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,15 +20,14 @@ import os import sys -import eventlet from oslo_config import cfg -from eventlet import wsgi from st2common import log as logging from st2common.service_setup import setup as common_setup from st2common.service_setup import teardown as common_teardown from st2common.service_setup import deregister_service from st2common.stream.listener import get_listener_if_set +from st2common.util import concurrency from st2common.util.wsgi import shutdown_server_kill_pending_requests from st2stream.signal_handlers import register_stream_signal_handlers from st2stream import config @@ -40,14 +39,6 @@ __all__ = ["main"] -eventlet.monkey_patch( - os=True, - select=True, - socket=True, - thread=False if "--use-debugger" in sys.argv else True, - time=True, -) - LOG = logging.getLogger(__name__) STREAM = "stream" @@ -76,6 +67,7 @@ def _setup(): def _run_server(): + host = cfg.CONF.stream.host port = cfg.CONF.stream.port @@ -83,13 +75,13 @@ def _run_server(): "(PID=%s) ST2 Stream API is serving on http://%s:%s.", os.getpid(), host, port ) - max_pool_size = eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS - worker_pool = eventlet.GreenPool(max_pool_size) - sock = eventlet.listen((host, port)) + max_pool_size = concurrency.get_default_green_pool_size() + worker_pool = concurrency.get_green_pool_class()(max_pool_size) + sock = concurrency.listen_server(host, port) def queue_shutdown(signal_number, stack_frame): deregister_service(STREAM) - eventlet.spawn_n( + concurrency.spawn( shutdown_server_kill_pending_requests, sock=sock, worker_pool=worker_pool, @@ -101,7 +93,7 @@ def queue_shutdown(signal_number, stack_frame): # will still want to kill long running stream requests. register_stream_signal_handlers(handler_func=queue_shutdown) - wsgi.server(sock, app.setup_app(), custom_pool=worker_pool) + concurrency.wsgi_server(sock, app.setup_app(), custom_pool=worker_pool) return 0 diff --git a/st2stream/tests/unit/controllers/v1/test_stream_execution_output.py b/st2stream/tests/unit/controllers/v1/test_stream_execution_output.py index ab9088056b..35d0cbed68 100644 --- a/st2stream/tests/unit/controllers/v1/test_stream_execution_output.py +++ b/st2stream/tests/unit/controllers/v1/test_stream_execution_output.py @@ -15,7 +15,7 @@ import json -import eventlet +from st2common.util import concurrency from six.moves import http_client @@ -50,7 +50,7 @@ def test_get_output_running_execution(self): # early enough for tests to pass. # NOTE: This only affects tests where listeners are not pre-initialized. listener = get_listener(name="execution_output") - eventlet.sleep(0.5) + concurrency.sleep(0.5) # Test the execution output API endpoint for execution which is running (blocking) status = action_constants.LIVEACTION_STATUS_RUNNING @@ -97,14 +97,14 @@ def publish_action_finished(action_execution_db): output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db) - eventlet.sleep(0.5) + concurrency.sleep(0.5) # Transition execution to completed state so the connection closes action_execution_db.status = action_constants.LIVEACTION_STATUS_SUCCEEDED action_execution_db = ActionExecution.add_or_update(action_execution_db) - eventlet.spawn_after(0.2, insert_mock_data) - eventlet.spawn_after(1.0, publish_action_finished, action_execution_db) + concurrency.spawn_after(0.2, insert_mock_data) + concurrency.spawn_after(1.0, publish_action_finished, action_execution_db) # Retrieve data while execution is running - endpoint return new data once it's available # and block until the execution finishes diff --git a/st2tests/conf/st2.conf b/st2tests/conf/st2.conf index 0801ccc4a7..b0b7e8e961 100644 --- a/st2tests/conf/st2.conf +++ b/st2tests/conf/st2.conf @@ -28,6 +28,7 @@ logging = st2auth/conf/logging.conf [system] base_path = /opt/stackstorm +concurrency_library = gevent [syslog] host = 127.0.0.1 diff --git a/st2tests/integration/orquesta/test_performance.py b/st2tests/integration/orquesta/test_performance.py index 899b3090f9..a5a71a40c7 100644 --- a/st2tests/integration/orquesta/test_performance.py +++ b/st2tests/integration/orquesta/test_performance.py @@ -17,13 +17,13 @@ from __future__ import absolute_import -import eventlet import json from integration.orquesta import base from six.moves import range from st2common.constants import action as ac_const +from st2common.util import concurrency class WiringTest(base.TestWorkflowExecution): @@ -35,7 +35,7 @@ def test_concurrent_load(self): wf_input = {"vm_name": "demo1", "meta": {"demo1.itests.org": "10.3.41.99"}} exs = [self._execute_workflow(wf_name, wf_input) for i in range(load_count)] - eventlet.sleep(delay_poll) + concurrency.sleep(delay_poll) for ex in exs: e = self._wait_for_completion(ex) diff --git a/st2tests/integration/orquesta/test_wiring_error_handling.py b/st2tests/integration/orquesta/test_wiring_error_handling.py index edaba668a1..c56eef0814 100644 --- a/st2tests/integration/orquesta/test_wiring_error_handling.py +++ b/st2tests/integration/orquesta/test_wiring_error_handling.py @@ -15,10 +15,10 @@ from __future__ import absolute_import -import eventlet from integration.orquesta import base from st2common.constants import action as ac_const +from st2common.util import concurrency class ErrorHandlingTest(base.TestWorkflowExecution): @@ -269,7 +269,7 @@ def test_remediate_then_fail(self): # tasks are written. To avoid that, we use longer sleep delay here. # Better approach would be to try to retry a couple of times until expected num of # tasks is reached (With some hard limit) before failing - eventlet.sleep(2) + concurrency.sleep(2) self._wait_for_task(ex, "task1", ac_const.LIVEACTION_STATUS_FAILED) self._wait_for_task(ex, "log", ac_const.LIVEACTION_STATUS_SUCCEEDED) diff --git a/st2tests/integration/orquesta/test_wiring_inquiry.py b/st2tests/integration/orquesta/test_wiring_inquiry.py index b6bf922758..430f9749b3 100644 --- a/st2tests/integration/orquesta/test_wiring_inquiry.py +++ b/st2tests/integration/orquesta/test_wiring_inquiry.py @@ -15,11 +15,10 @@ from __future__ import absolute_import -import eventlet - from integration.orquesta import base from st2common.constants import action as ac_const +from st2common.util import concurrency class InquiryWiringTest(base.TestWorkflowExecution): @@ -75,7 +74,7 @@ def test_parallel_inquiries(self): ) # Allow some time for the first inquiry to get processed. - eventlet.sleep(2) + concurrency.sleep(2) # Respond to the second inquiry. t2_ac_exs = self._wait_for_task( diff --git a/st2tests/requirements.txt b/st2tests/requirements.txt index 27f69000ae..467f1ce5b0 100644 --- a/st2tests/requirements.txt +++ b/st2tests/requirements.txt @@ -7,7 +7,7 @@ # update the component requirements.txt RandomWords mock==5.2.0 -psutil==7.1.0 +psutil==7.2.2 pyrabbit pytest==7.0.1 -webtest==3.0.1 +webtest==3.0.7 diff --git a/st2tests/st2tests/__init__.py b/st2tests/st2tests/__init__.py index fc60bd0728..502ebd0575 100644 --- a/st2tests/st2tests/__init__.py +++ b/st2tests/st2tests/__init__.py @@ -15,6 +15,7 @@ from __future__ import absolute_import +from st2tests.base import GreenThreadTestCase from st2tests.base import EventletTestCase from st2tests.base import DbTestCase from st2tests.base import ExecutionDbTestCase @@ -23,6 +24,7 @@ __all__ = [ + "GreenThreadTestCase", "EventletTestCase", "DbTestCase", "ExecutionDbTestCase", diff --git a/st2tests/st2tests/base.py b/st2tests/st2tests/base.py index b452f79983..cf03ba2f0a 100644 --- a/st2tests/st2tests/base.py +++ b/st2tests/st2tests/base.py @@ -36,8 +36,8 @@ import logging import six -import eventlet import psutil +from st2common.util import concurrency import mock from oslo_config import cfg from unittest import TestCase @@ -178,27 +178,25 @@ def _register_pack_configs(self, validate_configs=False): registrar.register_from_packs(base_dirs=get_packs_base_paths()) -class EventletTestCase(TestCase): +class GreenThreadTestCase(TestCase): """ - Base test class which performs eventlet monkey patching before the tests run - and un-patching after the tests have finished running. + Base test class which performs eventlet/gevent monkey patching before the tests run. """ @classmethod def setUpClass(cls): - eventlet.monkey_patch( - os=True, - select=True, - socket=True, - thread=False if "--use-debugger" in sys.argv else True, - time=True, - ) + monkey_patch() @classmethod def tearDownClass(cls): - eventlet.monkey_patch( - os=False, select=False, socket=False, thread=False, time=False - ) + # NOTE: Intentionally does not call super().tearDownClass() - subclasses that mix this + # in with a DB test case (e.g. ExecutionDbTestCase) rely on this stopping the MRO chain + # here rather than triggering that base class' DB teardown. + pass + + +class EventletTestCase(GreenThreadTestCase): + """Deprecated alias for GreenThreadTestCase, kept for external callers.""" class BaseDbTestCase(BaseTestCase): @@ -360,7 +358,7 @@ def _wait_on_status( assert isinstance(status, six.string_types), "%s is not of text type" % (status) for _ in range(0, retries): - eventlet.sleep(delay) + concurrency.sleep(delay) liveaction_db = LiveAction.get_by_id(str(liveaction_db.id)) if liveaction_db.status == status: break @@ -378,7 +376,7 @@ def _wait_on_statuses( ) for _ in range(0, retries): - eventlet.sleep(delay) + concurrency.sleep(delay) liveaction_db = LiveAction.get_by_id(str(liveaction_db.id)) if liveaction_db.status in statuses: break @@ -392,7 +390,7 @@ def _wait_on_ac_ex_status( self, execution_db, status, retries=300, delay=0.1, raise_exc=True ): for _ in range(0, retries): - eventlet.sleep(delay) + concurrency.sleep(delay) execution_db = ex_db_access.ActionExecution.get_by_id(str(execution_db.id)) if execution_db.status == status: break @@ -406,7 +404,7 @@ def _wait_on_call_count( self, mocked, expected_count, retries=100, delay=0.1, raise_exc=True ): for _ in range(0, retries): - eventlet.sleep(delay) + concurrency.sleep(delay) if mocked.call_count == expected_count: break @@ -820,18 +818,23 @@ def get_resources_path(): return os.path.join(os.path.dirname(__file__), "resources") -def blocking_eventlet_spawn(func, *args, **kwargs): +def blocking_concurrency_spawn(func, *args, **kwargs): func(*args, **kwargs) return mock.Mock() +def blocking_eventlet_spawn(func, *args, **kwargs): + """Deprecated alias for blocking_concurrency_spawn(), kept for external callers.""" + return blocking_concurrency_spawn(func, *args, **kwargs) + + # Utility function for mocking read_and_store_{stdout,stderr} functions def make_mock_stream_readline(mock_stream, mock_data, stop_counter=1, sleep_delay=0): mock_stream.counter = 0 def mock_stream_readline(): if sleep_delay: - eventlet.sleep(sleep_delay) + concurrency.sleep(sleep_delay) if mock_stream.counter >= stop_counter: mock_stream.closed = True diff --git a/st2tests/st2tests/mocks/execution.py b/st2tests/st2tests/mocks/execution.py index 00e3c8ef11..d54defeb19 100644 --- a/st2tests/st2tests/mocks/execution.py +++ b/st2tests/st2tests/mocks/execution.py @@ -14,9 +14,10 @@ # limitations under the License. from __future__ import absolute_import -import eventlet import traceback +from st2common.util import concurrency + from st2actions.notifier import notifier from st2common.models.db.execution import ActionExecutionDB @@ -40,7 +41,7 @@ class MockExecutionPublisherNonBlocking(object): def publish_update(cls, payload): try: if isinstance(payload, ActionExecutionDB): - eventlet.spawn(notifier.get_notifier().process, payload) + concurrency.spawn(notifier.get_notifier().process, payload) except Exception: traceback.print_exc() print(payload) diff --git a/st2tests/st2tests/mocks/liveaction.py b/st2tests/st2tests/mocks/liveaction.py index 2b329e6b25..3a7a696d79 100644 --- a/st2tests/st2tests/mocks/liveaction.py +++ b/st2tests/st2tests/mocks/liveaction.py @@ -17,9 +17,10 @@ from __future__ import print_function import six -import eventlet import traceback +from st2common.util import concurrency + from st2actions import worker from st2actions.scheduler import entrypoint as scheduling from st2actions.scheduler import handler as scheduling_queue @@ -79,10 +80,10 @@ def publish_state(cls, payload, state): try: if isinstance(payload, LiveActionDB): if state == action_constants.LIVEACTION_STATUS_REQUESTED: - thread = eventlet.spawn(cls.process, payload) + thread = concurrency.spawn(cls.process, payload) cls.threads.append(thread) else: - thread = eventlet.spawn(worker.get_worker().process, payload) + thread = concurrency.spawn(worker.get_worker().process, payload) cls.threads.append(thread) except Exception: traceback.print_exc() @@ -92,13 +93,13 @@ def publish_state(cls, payload, state): def wait_all(cls): for thread in cls.threads: try: - thread.wait() + concurrency.wait(thread) except Exception as e: print(six.text_type(e)) finally: cls.threads.remove(thread) - eventlet.sleep(0.1) + concurrency.sleep(0.1) class MockLiveActionPublisherSchedulingQueueOnly(object): diff --git a/st2tests/st2tests/mocks/workflow.py b/st2tests/st2tests/mocks/workflow.py index 051bf5cb83..f9c8180df2 100644 --- a/st2tests/st2tests/mocks/workflow.py +++ b/st2tests/st2tests/mocks/workflow.py @@ -16,9 +16,10 @@ from __future__ import absolute_import import six -import eventlet import traceback +from st2common.util import concurrency + from st2actions.workflows import workflows from st2common.models.db import workflow as wf_ex_db @@ -53,7 +54,7 @@ class MockWorkflowExecutionPublisherNonBlocking(object): def publish_create(cls, payload): try: if isinstance(payload, wf_ex_db.WorkflowExecutionDB): - thread = eventlet.spawn(workflows.get_engine().process, payload) + thread = concurrency.spawn(workflows.get_engine().process, payload) cls.threads.append(thread) except Exception: traceback.print_exc() @@ -63,7 +64,7 @@ def publish_create(cls, payload): def publish_state(cls, payload, state): try: if isinstance(payload, wf_ex_db.WorkflowExecutionDB): - thread = eventlet.spawn(workflows.get_engine().process, payload) + thread = concurrency.spawn(workflows.get_engine().process, payload) cls.threads.append(thread) except Exception: traceback.print_exc() @@ -73,7 +74,7 @@ def publish_state(cls, payload, state): def wait_all(cls): for thread in cls.threads: try: - thread.wait() + concurrency.wait(thread) except Exception as e: print(six.text_type(e)) finally: diff --git a/test-requirements.txt b/test-requirements.txt index a17c5b499c..7ab9cdf9be 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -25,16 +25,16 @@ alabaster<0.7.14 # Required by st2client tests pyyaml==6.0.3 # Constrain pygments required by editor to align with st2 core version -pygments==2.19.2 +pygments==2.21.0 RandomWords -gunicorn==23.0.0 -psutil==7.1.0 -webtest==3.0.1 +gunicorn==25.3.0 +psutil==7.2.2 +webtest==3.0.7 # Bump to latest to meet sphinx requirements. rstcheck==6.2.1 tox==4.14.2 pyrabbit -prance==25.4.8.0 +prance==26.7.19.0 # pip-tools provides pip-compile: to check for version conflicts pip-tools==7.5.3 pytest==7.0.1 @@ -45,8 +45,8 @@ pytest-xdist==2.5.0 # for Makefile-based pytest runs pytest-custom_exit_code # zstandard is used for micro benchmarks -zstandard==0.23.0 +zstandard==0.25.0 # ujson is used for micro benchmarks -ujson==5.10.0 +ujson==5.13.0 # needed by integration tests for coordination -redis==6.1.1 +redis==8.1.0 diff --git a/tools/launchdev.sh b/tools/launchdev.sh index 26b4b92268..848aed2d14 100755 --- a/tools/launchdev.sh +++ b/tools/launchdev.sh @@ -198,6 +198,15 @@ function st2start() fi echo -n "Using content packs base dir: "; iecho "$PACKS_BASE_DIR" + # Gunicorn worker class must match the concurrency library st2 itself is using + # (see st2common.util.concurrency), or the WSGI worker will hang: gevent's monkey + # patching happening under gunicorn's eventlet worker (or vice versa) doesn't work. + CONCURRENCY_LIBRARY=$(grep 'concurrency_library' ${ST2_CONF} | awk 'BEGIN {FS=" = "}; {print $2}') + if [ -z "$CONCURRENCY_LIBRARY" ]; then + CONCURRENCY_LIBRARY="gevent" + fi + echo -n "Using concurrency library: "; iecho "$CONCURRENCY_LIBRARY" + # Copy and overwrite the action contents if [ ! -d "$ST2_BASE_DIR" ]; then wecho "$ST2_BASE_DIR doesn't exist. Creating ..." @@ -266,7 +275,7 @@ function st2start() # Run the st2 API server if [ "${use_gunicorn}" = true ]; then echo 'Starting st2-api using gunicorn ...' - tmux new-session -d -s st2-api "${PRE_SCRIPT}; ${VIRTUALENV}/bin/gunicorn st2api.wsgi:application -k eventlet -b $BINDING_ADDRESS:9101 --workers 1 2>&1 | tee -a ${ST2_LOGS}/st2-api.log" + tmux new-session -d -s st2-api "${PRE_SCRIPT}; ${VIRTUALENV}/bin/gunicorn st2api.wsgi:application -k ${CONCURRENCY_LIBRARY} -b $BINDING_ADDRESS:9101 --workers 1 2>&1 | tee -a ${ST2_LOGS}/st2-api.log" else echo 'Starting st2-api ...' tmux new-session -d -s st2-api "${PRE_SCRIPT}; ${VIRTUALENV}/bin/python ./st2api/bin/st2api --config-file $ST2_CONF 2>&1 | tee -a ${ST2_LOGS}/st2-api.log" @@ -275,7 +284,7 @@ function st2start() # Run st2stream API server if [ "${use_gunicorn}" = true ]; then echo 'Starting st2-stream using gunicorn ...' - tmux new-session -d -s st2-stream "${PRE_SCRIPT}; ${VIRTUALENV}/bin/gunicorn st2stream.wsgi:application -k eventlet -b $BINDING_ADDRESS:9102 --workers 1 2>&1 | tee -a ${ST2_LOGS}/st2-stream.log" + tmux new-session -d -s st2-stream "${PRE_SCRIPT}; ${VIRTUALENV}/bin/gunicorn st2stream.wsgi:application -k ${CONCURRENCY_LIBRARY} -b $BINDING_ADDRESS:9102 --workers 1 2>&1 | tee -a ${ST2_LOGS}/st2-stream.log" else echo 'Starting st2-stream ...' tmux new-session -d -s st2-stream "${PRE_SCRIPT}; ${VIRTUALENV}/bin/python ./st2stream/bin/st2stream --config-file $ST2_CONF 2>&1 | tee -a ${ST2_LOGS}/st2-stream.log" @@ -340,7 +349,7 @@ function st2start() # Run the auth API server if [ "${use_gunicorn}" = true ]; then echo 'Starting st2-auth using gunicorn ...' - tmux new-session -d -s st2-auth "${PRE_SCRIPT}; ${VIRTUALENV}/bin/gunicorn st2auth.wsgi:application -k eventlet -b $BINDING_ADDRESS:9100 --workers 1 2>&1 | tee -a ${ST2_LOGS}/st2-auth.log" + tmux new-session -d -s st2-auth "${PRE_SCRIPT}; ${VIRTUALENV}/bin/gunicorn st2auth.wsgi:application -k ${CONCURRENCY_LIBRARY} -b $BINDING_ADDRESS:9100 --workers 1 2>&1 | tee -a ${ST2_LOGS}/st2-auth.log" else echo 'Starting st2-auth ...' tmux new-session -d -s st2-auth "${PRE_SCRIPT}; ${VIRTUALENV}/bin/python ./st2auth/bin/st2auth --config-file $ST2_CONF 2>&1 | tee -a ${ST2_LOGS}/st2-auth.log" diff --git a/tools/queue_producer.py b/tools/queue_producer.py index 01476a26b8..4b3ea4f42c 100755 --- a/tools/queue_producer.py +++ b/tools/queue_producer.py @@ -22,18 +22,18 @@ import argparse -import eventlet from kombu import Exchange from st2common import config from st2common.transport.publishers import PoolPublisher +from st2common.util import concurrency def main(exchange, routing_key, payload): exchange = Exchange(exchange, type="topic") publisher = PoolPublisher() publisher.publish(payload=payload, exchange=exchange, routing_key=routing_key) - eventlet.sleep(0.5) + concurrency.sleep(0.5) if __name__ == "__main__": diff --git a/tools/st2-inject-trigger-instances.py b/tools/st2-inject-trigger-instances.py index 79b0f18e25..b627f193be 100755 --- a/tools/st2-inject-trigger-instances.py +++ b/tools/st2-inject-trigger-instances.py @@ -30,12 +30,12 @@ import os import random -import eventlet from oslo_config import cfg import yaml from st2common import config from st2common.util.monkey_patch import monkey_patch +from st2common.util import concurrency from st2common.util import date as date_utils from st2common.transport.reactor import TriggerDispatcher @@ -67,7 +67,7 @@ def _inject_instances( # NOTE: We decrease sleep delay for 56% to take into account overhead / delay because # of the call to dispatchet.dispatch method. delta = random.expovariate(rate_per_trigger) - eventlet.sleep(delta * 0.56) + concurrency.sleep(delta * 0.56) elapsed = (date_utils.get_datetime_utc_now() - start).seconds count += 1 @@ -155,11 +155,12 @@ def main(): rate = 0 rate_per_trigger = 0 - dispatcher_pool = eventlet.GreenPool(len(triggers)) + dispatcher_pool = concurrency.get_green_pool_class()(len(triggers)) for trigger in triggers: payload = trigger_payload_schema.get(trigger, {}) - dispatcher_pool.spawn( + concurrency.pool_spawn( + dispatcher_pool, _inject_instances, trigger, rate_per_trigger, @@ -167,8 +168,8 @@ def main(): payload=payload, max_throughput=max_throughput, ) - eventlet.sleep(random.uniform(0, 1)) - dispatcher_pool.waitall() + concurrency.sleep(random.uniform(0, 1)) + concurrency.green_pool_wait_all(dispatcher_pool) if __name__ == "__main__":